505

I am using

import requests
requests.post(url='https://foo.example', data={'bar':'baz'})

but I get a request.exceptions.SSLError. The website has an expired certficate, but I am not sending sensitive data, so it doesn't matter to me. I would imagine there is an argument like 'verifiy=False' that I could use, but I can't seem to find it.

0

13 Answers 13

877

From the documentation:

requests can also ignore verifying the SSL certificate if you set verify to False.

>>> requests.get('https://kennethreitz.com', verify=False)
<Response [200]>

If you're using a third-party module and want to disable the checks, here's a context manager that monkey patches requests and changes it so that verify=False is the default and suppresses the warning.

import warnings
import contextlib

import requests
from urllib3.exceptions import InsecureRequestWarning

old_merge_environment_settings = requests.Session.merge_environment_settings

@contextlib.contextmanager
def no_ssl_verification():
    opened_adapters = set()

    def merge_environment_settings(self, url, proxies, stream, verify, cert):
        # Verification happens only once per connection so we need to close
        # all the opened adapters once we're done. Otherwise, the effects of
        # verify=False persist beyond the end of this context manager.
        opened_adapters.add(self.get_adapter(url))

        settings = old_merge_environment_settings(self, url, proxies, stream, verify, cert)
        settings['verify'] = False

        return settings

    requests.Session.merge_environment_settings = merge_environment_settings

    try:
        with warnings.catch_warnings():
            warnings.simplefilter('ignore', InsecureRequestWarning)
            yield
    finally:
        requests.Session.merge_environment_settings = old_merge_environment_settings

        for adapter in opened_adapters:
            try:
                adapter.close()
            except:
                pass

Here's how you use it:

with no_ssl_verification():
    requests.get('https://wrong.host.badssl.example/')
    print('It works')

    requests.get('https://wrong.host.badssl.example/', verify=True)
    print('Even if you try to force it to')

requests.get('https://wrong.host.badssl.example/', verify=False)
print('It resets back')

session = requests.Session()
session.verify = True

with no_ssl_verification():
    session.get('https://wrong.host.badssl.example/', verify=True)
    print('Works even here')

try:
    requests.get('https://wrong.host.badssl.example/')
except requests.exceptions.SSLError:
    print('It breaks')

try:
    session.get('https://wrong.host.badssl.example/')
except requests.exceptions.SSLError:
    print('It breaks here again')

Note that this code closes all open adapters that handled a patched request once you leave the context manager. This is because requests maintains a per-session connection pool and certificate validation happens only once per connection so unexpected things like this will happen:

>>> import requests
>>> session = requests.Session()
>>> session.get('https://wrong.host.badssl.example/', verify=False)
/usr/local/lib/python3.7/site-packages/urllib3/connectionpool.py:857: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
  InsecureRequestWarning)
<Response [200]>
>>> session.get('https://wrong.host.badssl.example/', verify=True)
/usr/local/lib/python3.7/site-packages/urllib3/connectionpool.py:857: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
  InsecureRequestWarning)
<Response [200]>
21
  • 7
    Thanks, this works if you have few requests calls inside your own code, but imagine that I want to disable this in a third partly library that uses requests,... it would be impossible to fix the 3rd party lib like this.
    – sorin
    Commented Dec 17, 2013 at 18:49
  • 7
    @sorin: Just monkey patch requests and have verify default to False.
    – Blender
    Commented Dec 18, 2013 at 1:16
  • 2
    How do I suppress the big nasty warning message that still gets printed?
    – Michael
    Commented Jan 15, 2015 at 18:33
  • 40
    @Michael to answer my own question: requests.packages.urllib3.disable_warnings()
    – Michael
    Commented Jan 15, 2015 at 18:36
  • 23
    @Michael: or to avoid hiding all warnings: from urllib3.exceptions import InsecureRequestWarning then requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
    – Seb D.
    Commented Oct 4, 2017 at 13:38
201

Use requests.packages.urllib3.disable_warnings() and verify=False on requests methods.

Note that you can either import urllib3 directly or import it from requests.packages.urllib3 to be use to use the same version as the one in requests.

import requests

import urllib3  
# or if this does not work with the previous import:
# from requests.packages import urllib3  

# Suppress only the single warning from urllib3.
urllib3.disable_warnings(category=urllib3.exceptions.InsecureRequestWarning)

# Set `verify=False` on `requests.post`.
requests.post(url='https://example.com', data={'bar':'baz'}, verify=False)

And if you want to suppress the warning from urllib3 only when used by the requests methods, you can use it in a context manager:

with urllib3.warnings.catch_warnings():
   urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

   requests.post(url='https://example.com', data={'bar':'baz'}, verify=False)
6
  • 13
    Your answer is usefull when you want to get rid of Warnings like "Unverified HTTPS request is being made". But verify=False must to be present anyway. Tnx.
    – Lufa
    Commented Jan 27, 2016 at 11:29
  • 24
    And to avoid hiding all warnings: from urllib3.exceptions import InsecureRequestWarning then requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
    – Seb D.
    Commented Oct 4, 2017 at 13:38
  • 3
    For those who can't disable warnings, you can try requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning). This works because it ensures the urllib3.exceptions.InsecureRequestWarning is the exact one used by requests. Commented Feb 11, 2020 at 3:09
  • What happened security point of you, If we setup 'verify=False` with getting warning Unverified HTTP request.. ? another, If I set verify=True then request not work , getting error like request.exception.SSError..Max retries exceeded with url: ? which one best solution. Commented Apr 30, 2021 at 7:28
  • Would I want to reset this after the requests call so that these warnings show up again? How would I re-enable the warnings?
    – Eric C.
    Commented Dec 14, 2022 at 15:25
76

To add to Blender's answer, you can disable SSL certificate validation for all requests using Session.verify = False

import requests

session = requests.Session()
session.verify = False
session.post(url='https://example.com', data={'bar':'baz'})

Note that urllib3, (which Requests uses), strongly discourages making unverified HTTPS requests and will raise an InsecureRequestWarning.

1
  • 1
    still I need to set this session.trust_env = False to make it work due to **CA_BUNDLE variable.
    – imbr
    Commented Sep 30, 2021 at 17:11
42

Also can be done with a environment variable:

export CURL_CA_BUNDLE=""
5
  • 4
    This gives me: "OSError: Could not find a suitable TLS CA certificate bundle, invalid path: "" . I'm using request 2.22.0
    – chaim
    Commented Nov 26, 2019 at 10:46
  • 5
    or export REQUESTS_CA_BUNDLE='your-ca.pem'
    – weaming
    Commented Nov 28, 2019 at 14:49
  • 3
    This seems to be the best answer in case you need to use a library that you cannot edit
    – user989762
    Commented May 11, 2020 at 14:59
  • Based on CURL_CA_BUNDLE, os.environ['REQUESTS_CA_BUNDLE'] = 'FiddlerRootCertificate_Base64_Encoded_X.509.cer.pem' # your-ca.pem works for Python 3.8.3 when using google-cloud-bigquery 1.24.0 and BigQuery Client Lib for Python
    – samm
    Commented May 20, 2020 at 10:30
  • 3
    export CURL_CA_BUNDLE="" seems to no longer work after 2.28.0. From pyup.io/packages/pypi/requests/changelog --- Fixed bug where setting CURL_CA_BUNDLE to an empty string would disable cert verification. All Requests 2.x versions before 2.28.0 are affected. (6074) Commented Jun 28, 2023 at 16:33
19

If you are writing a scraper and really don't care about the SSL certificate you can set it global:

import ssl

ssl._create_default_https_context = ssl._create_unverified_context

DO NOT USE IN PRODUCTION

edit, comment from @Misty

Not working. Requests now uses urllib3, which create its own SSLContext. You can override cert_reqs instead

ssl.SSLContext.verify_mode = property(lambda self: ssl.CERT_NONE, lambda self, newval: None)
2
  • 3
    Not working. Requests now uses urllib3, which create its own SSLContext. You can override cert_reqs instead ssl.SSLContext.verify_mode = property(lambda self: ssl.CERT_NONE, lambda self, newval: None)
    – Misty
    Commented May 17, 2022 at 4:34
  • 1
    @Misty Good addition thanks! indeed answer is for previous versions (2021) Commented May 21, 2022 at 12:25
13

If you want to send exactly post request with verify=False option, fastest way is to use this code:

import requests

requests.api.request('post', url, data={'bar':'baz'}, json=None, verify=False)
2
  • Bandit won't be happy when you disable verify=False. See: docs.openstack.org/bandit/latest/plugins/…
    – kRazzy R
    Commented Aug 13, 2018 at 22:12
  • 2
    Hi there, I have a request that gives me the response of post request in the Postman by disabling the 'SSL certificate verification' in the setting option. But, if I get the python request code that provided by the Postman, I will receive the "SSL routines', 'tls_process_server_certificate', 'certificate verify failed" error and adding the 'verify=False' does not help in this case, Is there any solution to get the response of the Postman in the python request script? Commented Jun 1, 2020 at 6:00
13

What has worked for me Due verify=False Bug

Due to a bug on session.verify=False that makes urllib* ignore
that when a environment variable (CURL_CA_BUNDLE) is set. So we set it to nothing.

import requests, os
session = requests.Session()
session.verify = False
session.trust_env = False
os.environ['CURL_CA_BUNDLE']="" # or whaever other is interfering with 
session.post(url='https://example.com', data={'bar':'baz'})

Not sure I need trust_env

5

You can disable ssl verification globally and also disable the warnings using the below approach in the entry file of your code

import requests

# disable ssl warning
requests.packages.urllib3.disable_warnings()

# override the methods which you use
requests.post = lambda url, **kwargs: requests.request(
    method="POST", url=url, verify=False, **kwargs
)

requests.get = lambda url, **kwargs: requests.request(
    method="GET", url=url, verify=False, **kwargs
)
3

Bit late to the party.

In python 3.8 and requests (2.28.2) it is possible to disable those warnings on urllib3(https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html#ssl-warnings) via requests i.e.

import requests
requests.urllib3.disable_warnings()
2

python 3.6+

import warnings
warnings.filterwarnings("ignore", message="Unverified HTTPS request")
2

If you work with websockets package then ssl package provides ssl._create_unverified_context() method, that disables certificates verification. I had to use it for my websocket app that uses self singed ssl certificates.

Example

import ssl


ctx = ssl._create_unverified_context()
url = f"wss://localhost:8001/ws/v1/alert"

async with websockets.connect(url, ssl=ctx) as websocket:
    pass
1

first import ssl then make a variable like this with three lines of code in your python script file-

ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE

An Example that I have use in html parsing with beautifulsoup was like this -

import urllib.request,urllib.parse,urllib.error

from bs4 import BeautifulSoup
import ssl

ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE


url = input('Enter - ')
html = urllib.request.urlopen(url, context=ctx).read()
soup = BeautifulSoup(html, 'html.parser')
1

If you want to disable SSL verification globally (not a good idea, but it has its uses), as Authlib states:

You can force all requests to disable SSL verification by setting your environment variable CURL_CA_BUNDLE="".

However, requests uses the enviroment variable REQUESTS_CA_BUNDLE in order to list all CAs, but you can force it to "fall back" on CURL_CA_BUNDLE.

In their documentation:

This list of trusted CAs can also be specified through the REQUESTS_CA_BUNDLE environment variable. If REQUESTS_CA_BUNDLE is not set, CURL_CA_BUNDLE will be used as fallback.

So, you can just change the enviroment variables at the begining of your script:

import os

os.environ['REQUESTS_CA_BUNDLE'] = ""
os.environ['CURL_CA_BUNDLE'] = ""  # in most instances you don't even need this

Not the answer you're looking for? Browse other questions tagged or ask your own question.