Making HTTPS Requests secure in Python

October 30, 2011 at 05:07 PM | categories: Programming | View Comments

Python 2.7 does not automatically validate certificates on HTTPS requests. The following seems to be the cleanest, though not necessarily fully secure method to get there.

This will work with:

It may work with other libs that depend on the HTTPSConnection class from httplib in the Python Standard Library.

import httplib
import socket
import ssl
from backports.ssl_match_hostname import match_hostname

def install_validating_https(cert_file):
    def validating_connect(self):
        "Connect to a host on a given (SSL) port."

        sock = socket.create_connection((, self.port),
                                        self.timeout, self.source_address)
        if self._tunnel_host:
            self.sock = sock
        self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, cert_reqs=ssl.CERT_REQUIRED, ca_certs=cert_file)

    httplib.HTTPSConnection.connect = validating_connect

Okay, that's the basics. backports.ssl_match_hostname is available in pypi, the rest is stdlib. This should work with 2.6+, for < 2.6 you'll want to get the ssl library from pypi (I don't know the implications for the HTTPSConnection lib for anything other than 2.7).

Somewhere in your app, call install_validating_https and pass it the path to your root ca collection file. Oh, wait, what's that? Well it probably would be a pem encoding of the Mozilla NSS certdata.txt. The pem encoding can be done with the script that comes with M2Crypto or you can get a pre-built one from the curl project (depending on your level of paranoia since you can't download the curl version over https).

Much of the initial info that went into my final solution came from the SSL Topic on the Python Wiki and the "How to validate SSL Certificates with Python" question on Stack Overflow with a sprinkling of Python bug reports.

Read and Post Comments