using requests with TLS doesn't give SNI support

PythonSslSsl CertificatePython RequestsSni

Python Problem Overview


I'm using requests to communicate with a django app but

When I try

requests.get('https://mysite.com', verify=True)

I get the error: > hostname 'mysite.com' doesn't match either of '*.myhost.com', 'myhost.com'

However, when I look at the browser, or http://www.digicert.com/help/ the certificate looks fine and dandy.

My host suggested it was the lack of SNI support from requests (and Github seems to confirm that https://github.com/kennethreitz/requests/issues/749 ). Has anyone found a work-around using requests?

Python Solutions


Solution 1 - Python

The current version of Requests should be just fine with SNI. Further down the GitHub issue you can see the requirements:

Try installing those packages and then give it another shot.

EDIT: As of Requests v2.12.1, ndg-httpsclient and pyasn1 are no longer required. The full list of required packages is now:

Solution 2 - Python

In order for me to get the accepted answer to work, I had to install a bunch of other packages, in this order:

  • yum install libffi-devel
  • yum install gcc
  • yum install openssl-devel
  • pip install urllib3
  • pip install pyopenssl
  • pip install ndg-httpsclient
  • pip install pyasn1

Solution 3 - Python

Install requests module like this. This will install the security package extras.

pip install requests[security]

Solution 4 - Python

Or you can just use Python 2.7.9 and up:

"The entirety of Python 3.4's ssl module has been backported for Python 2.7.9. See PEP 466 for justification."

https://www.python.org/downloads/release/python-279/

Solution 5 - Python

@Lukasa answer is correct with the present (from github) requests. Remember to add OpenSSL in your system too apart from the pip dependencies he mentions.

If for deployment reasons you prefer a stable requests version like the 1.2.3 in pip, you can monkey patch that one to work with SNI like this:

import requests


def fileno(self):
    return self.socket.fileno()


def close(self):
    return self.connection.shutdown()


requests.pyopenssl.WrappedSocket.close = close
requests.pyopenssl.WrappedSocket.fileno = fileno

Solution 6 - Python

Copy my answer from Accessing https sites with IP address

On MAC High Sierra and Python 3.6.4, I tried the solution: requests toolbelt:HostHeaderSSLAdapter 1st, unfortunately, it doesn't work for me, then I tried forcediphttpsadapter, got it works finally.

The author explains everything in the readme part and has provided a sample script and it can be followed easily.

1.Install the library by pip install requests[security] forcediphttpsadapter

2.run the sample script:

import requests
from forcediphttpsadapter.adapters import ForcedIPHTTPSAdapter
session = requests.Session()
session.mount("https://example.com", ForcedIPHTTPSAdapter(dest_ip='1.2.3.4'))
response = session.get(
    '/some/path', headers={'Host': 'example.com'}, verify=False)

Note: For some cases, you may need to remove the prefix: 'www' from the url.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMassagranView Question on Stackoverflow
Solution 1 - PythonLukasaView Answer on Stackoverflow
Solution 2 - PythonShane NView Answer on Stackoverflow
Solution 3 - PythonNandeeshView Answer on Stackoverflow
Solution 4 - PythonstantonkView Answer on Stackoverflow
Solution 5 - PythonAntonioMOView Answer on Stackoverflow
Solution 6 - PythonXb74DkjbView Answer on Stackoverflow