Using Requests with Tls Doesn't Give Sni Support

using requests with TLS doesn't give SNI support

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

  • pyOpenSSL
  • ndg-httpsclient
  • pyasn1

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:

  • pyOpenSSL
  • idna

Python Requests SSL Error 504

The server requires SNI (server name indication) and will cause a TLS alert if the SNI extension is not used. SNI is available with python 3 and with python 2.7.9+. For older versions of python see using requests with TLS doesn't give SNI support.

SSL and TLS in Python requests

Requests uses the Python standard library ssl module under the hood - this supports various versions of SSL and TLS. You can tell requests to use a specific protocol (like TLSv1) by creating an HTTPAdapter that customizes the PoolManager instance that gets created.

I had to do something like this, but was bitten by the fact that we were also going via a proxy - in that case the init_poolmanager method isn't called, because it uses a ProxyManager instead. I used this:

class ForceTLSV1Adapter(adapters.HTTPAdapter):
"""Require TLSv1 for the connection"""
def init_poolmanager(self, connections, maxsize, block=False):
# This method gets called when there's no proxy.
self.poolmanager = poolmanager.PoolManager(
num_pools=connections,
maxsize=maxsize,
block=block,
ssl_version=ssl.PROTOCOL_TLSv1,
)

def proxy_manager_for(self, proxy, **proxy_kwargs):
# This method is called when there is a proxy.
proxy_kwargs['ssl_version'] = ssl.PROTOCOL_TLSv1
return super(ForceTLSV1Adapter, self).proxy_manager_for(proxy, **proxy_kwargs)

Can SNI be enabled without problems to servers that do not support SNI in TLS handshake

SNI is an optional TLS extension ("server_name"). This means any proper TLS stack which does not explicitly support this extension will ignore it. SNI is widely used and all modern browsers have enabled it.

This gives some confidence that almost all sites should work if you use TLS with SNI enabled. There might be still some sites out there which use a broken TLS stack which will fail just because SNI is present. But these sites will fail too when accessed by a modern browser. Also, way more sites will fail if SNI is not present, like everything behind Cloudflare Free SSL. Thus enabling SNI by default and maybe dealing with the fallout of a very few broken sites is definitely better then dealing with lots of sites which don't work without SNI.

Why does Python's `requests` reject my SSL certificate, which browsers accept

You are using a requests library without support for SNI (server name indication), but you have multiple SSL certificates behind the same IP address which requires SNI. You can verify this with openssl s_client. Without given a name for SNI the server just gives the default certificate for this IP, which is *.webfaction.com:

openssl s_client -connect ram.rachum.com:443
...
0 ...CN=*.webfaction.com

But if you specify a hostname for SNI it returns the expected certificate:

openssl s_client -connect ram.rachum.com:443 -servername ram.rachum.com
...
0 ...CN=ram.rachum.com...

Maybe you need to upgrade your requests library and other modules too, see using requests with TLS doesn't give SNI support

How to simulate non-SNI browsers (without SNI support)?

You can use the most commonly used SSL library, OpenSSL. Windows binaries are available to download.

openssl s_client -connect domain.com:443 command serves very well to test SSL connection from client side. It doesn't support SNI by default. You can append -servername domain.com argument to enable SNI.

Python requests SSL certificate verification fails, even after adding CA certificates

You need to install pyopenssl and ndg-httpsclient

See using requests with TLS doesn't give SNI support for more details



Related Topics



Leave a reply



Submit