user3480498
user3480498

Reputation: 141

How to disable hostname checking in requests python

I'm using Requests to connect to a RESTful API. The server I would like to reach use ssl with self-singed certificate.

cafile = "gateway.pem"
r = requests.get(request, auth=('admin', 'password'), verify=cafile)

the problem is I'm getting SSLError of hostname mismatch. there should be a way to disable the hostname checking without disabling certificate validation, as in many java implementations, but I can't find how to do it with requests in python.

stacktrace:

Traceback (most recent call last):
  File "<pyshell#43>", line 1, in <module>
    r = requests.get(request, auth=("admin", "password"), verify='gateway.pem')
  File "C:\Python27\lib\site-packages\requests-2.0.0-py2.7.egg\requests\api.py", line 55, in get
    return request('get', url, **kwargs)
  File "C:\Python27\lib\site-packages\requests-2.0.0-py2.7.egg\requests\api.py", line 44, in request
    return session.request(method=method, url=url, **kwargs)
  File "C:\Python27\lib\site-packages\requests-2.0.0-py2.7.egg\requests\sessions.py", line 357, in request
    resp = self.send(prep, **send_kwargs)
  File "C:\Python27\lib\site-packages\requests-2.0.0-py2.7.egg\requests\sessions.py", line 460, in send
    r = adapter.send(request, **kwargs)
  File "C:\Python27\lib\site-packages\requests-2.0.0-py2.7.egg\requests\adapters.py", line 358, in send
    raise SSLError(e)
SSLError: hostname '10.76.92.70' doesn't match u'lital.com'

How can this be done?

Upvotes: 14

Views: 39826

Answers (6)

mojoken
mojoken

Reputation: 1362

It looks like this feature has been added to the latest version of requests. I've verified and it's working for me - just pass verify=False on the request - as shown in the example in the documentation:

requests.get('https://api.github.com', verify=False)

Upvotes: -4

lane
lane

Reputation: 653

I'm a little late to the party but requests_toolbelt looks like it might help if you install version 0.7.0 or newer (my ubuntu 16.04 only has 0.6.0): https://toolbelt.readthedocs.io/en/latest/adapters.html#hostheaderssladapter

From the link:

Example usage:
>>> s.mount('https://', HostHeaderSSLAdapter())
>>> s.get("https://93.184.216.34", headers={"Host": "example.org"})

Upvotes: 8

user3644848
user3644848

Reputation: 1

If this is only for testing only then just add an entry in /etc/hosts to your local system (assuming you have access).

Upvotes: -5

Alecz
Alecz

Reputation: 2081

Did you look into the SSLContext.check_hostname parameter? You should be able to set it to False, and it should not check the hostname:

context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
context.verify_mode = ssl.CERT_REQUIRED
context.check_hostname = True
context.load_default_certs()

The only limitation is that this only works in Python 3.4 and later.

Reference: https://docs.python.org/3/library/ssl.html#ssl.SSLContext.check_hostname

Upvotes: 3

t-8ch
t-8ch

Reputation: 2713

Requests doesn't allow this directly, however you can provide a custom transport adapter which uses the features of the underlying urllib3. The usage of transport adapters is covered in the requests documentation.

This code is not tested, but should work.

from requests.adapters import HTTPAdapter
from requests.packages.urllib3.poolmanager import PoolManager


# Never check any hostnames
class HostNameIgnoringAdapter(HTTPAdapter):
    def init_poolmanager(self, connections, maxsize, block=False):
        self.poolmanager = PoolManager(num_pools=connections,
                                       maxsize=maxsize,
                                       block=block,
                                       assert_hostname=False)


# Check a custom hostname
class CustomHostNameCheckingAdapter(HTTPAdapter):
    def cert_verify(self, conn, url, verify, cert):
        #      implement me
        host = custom_function_mapping_url_to_hostname(url)
        conn.assert_hostname = host
        return super(CustomHostNameCheckingAdapter,
                     self).cert_verify(conn, url, verify, cert)

In detail the assert_hostname param works as follows: If None use the hostname from the URL, if False suppress hostname checking, if a custom string validate against this string.

Upvotes: 10

m.wasowski
m.wasowski

Reputation: 6387

http://docs.python-requests.org/en/latest/user/advanced/#ssl-cert-verification

verify keyword is a flag, not for providing certfile. You provided there non-empy string, which resolves to True in boolean context.

Use cert= keyword to provide path to certificate files, or disable verification with verify=False.

EDIT: although documentation says you can actually pass CA path to verify=, but there are no examples. It would be helpful to see whole traceback you are receiving.

Upvotes: -5

Related Questions