Python Requests throwing SSLError

860,011

Solution 1

The problem you are having is caused by an untrusted SSL certificate.

Like @dirk mentioned in a previous comment, the quickest fix is setting verify=False:

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

Please note that this will cause the certificate not to be verified. This will expose your application to security risks, such as man-in-the-middle attacks.

Of course, apply judgment. As mentioned in the comments, this may be acceptable for quick/throwaway applications/scripts, but really should not go to production software.

If just skipping the certificate check is not acceptable in your particular context, consider the following options, your best option is to set the verify parameter to a string that is the path of the .pem file of the certificate (which you should obtain by some sort of secure means).

So, as of version 2.0, the verify parameter accepts the following values, with their respective semantics:

  • True: causes the certificate to validated against the library's own trusted certificate authorities (Note: you can see which Root Certificates Requests uses via the Certifi library, a trust database of RCs extracted from Requests: Certifi - Trust Database for Humans).
  • False: bypasses certificate validation completely.
  • Path to a CA_BUNDLE file for Requests to use to validate the certificates.

Source: Requests - SSL Cert Verification

Also take a look at the cert parameter on the same link.

Solution 2

From requests documentation on SSL verification:

Requests can verify SSL certificates for HTTPS requests, just like a web browser. To check a host’s SSL certificate, you can use the verify argument:

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

If you don't want to verify your SSL certificate, make verify=False

Solution 3

The name of CA file to use you could pass via verify:

cafile = 'cacert.pem' # http://curl.haxx.se/ca/cacert.pem
r = requests.get(url, verify=cafile)

If you use verify=True then requests uses its own CA set that might not have CA that signed your server certificate.

Solution 4

I encountered the same issue and ssl certificate verify failed issue when using aws boto3, by review boto3 code, I found the REQUESTS_CA_BUNDLE is not set, so I fixed the both issue by setting it manually:

from boto3.session import Session
import os

# debian
os.environ['REQUESTS_CA_BUNDLE'] = os.path.join(
    '/etc/ssl/certs/',
    'ca-certificates.crt')
# centos
#   'ca-bundle.crt')

For aws-cli, I guess setting REQUESTS_CA_BUNDLE in ~/.bashrc will fix this issue (not tested because my aws-cli works without it).

REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt # ca-bundle.crt
export REQUESTS_CA_BUNDLE

Solution 5

$ pip install -U requests[security]

  • Tested on Python 2.7.6 @ Ubuntu 14.04.4 LTS
  • Tested on Python 2.7.5 @ MacOSX 10.9.5 (Mavericks)

When this question was opened (2012-05) the Requests version was 0.13.1. On version 2.4.1 (2014-09) the "security" extras were introduced, using certifi package if available.

Right now (2016-09) the main version is 2.11.1, that works good without verify=False. No need to use requests.get(url, verify=False), if installed with requests[security] extras.

Share:
860,011
TedBurrows
Author by

TedBurrows

Updated on July 12, 2022

Comments

  • TedBurrows
    TedBurrows almost 2 years

    I'm working on a simple script that involves CAS, jspring security check, redirection, etc. I would like to use Kenneth Reitz's python requests because it's a great piece of work! However, CAS requires getting validated via SSL so I have to get past that step first. I don't know what Python requests is wanting? Where is this SSL certificate supposed to reside?

    Traceback (most recent call last):
      File "./test.py", line 24, in <module>
      response = requests.get(url1, headers=headers)
      File "build/bdist.linux-x86_64/egg/requests/api.py", line 52, in get
      File "build/bdist.linux-x86_64/egg/requests/api.py", line 40, in request
      File "build/bdist.linux-x86_64/egg/requests/sessions.py", line 209, in request 
      File "build/bdist.linux-x86_64/egg/requests/models.py", line 624, in send
      File "build/bdist.linux-x86_64/egg/requests/models.py", line 300, in _build_response
      File "build/bdist.linux-x86_64/egg/requests/models.py", line 611, in send
    requests.exceptions.SSLError: [Errno 1] _ssl.c:503: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
    
  • TedBurrows
    TedBurrows almost 12 years
    Well, I added the verify=True, but still received the exact same error. No change. Something else must be required, but don't know what it could be.
  • TedBurrows
    TedBurrows almost 12 years
    I suppose I have now descended into SSL madness. I added this to my initial get...get(url1, headers=headers, cert='/etc/pki/tls/cert.pem', verify=True, config=my_config) So, now I am getting this error. requests.exceptions.SSLError: [Errno 336265225] _ssl.c:351: error:140B0009:SSL routines:SSL_CTX_use_PrivateKey_file:PEM lib I have not a clue what this means.
  • TedBurrows
    TedBurrows almost 12 years
    Reading thru tons of documents I have learned I don't need the verify=True. That is for validating the certificate from the server. I don't need to do that because the server and the CAS server do that together. So basically, when you do a 'get' to the primary server, you get redirected to the CAS using https (which is ssl). So basically, the verify=True doesn't apply in this case. Still doesn't help me but maybe will help someone else who reads this.
  • Dirk
    Dirk almost 12 years
    Just set verify=False if you don't want to validate the certificate, iow if you have a self signed certificate
  • diyism
    diyism about 11 years
    Yes, when i used dotCloud in ubuntu, the same "certificate verify failed" came out. After modified "requests.session(headers=headers, hooks=hooks, verify=False)" in "/usr/local/lib/python2.6/dist-packages/dotcloud/client/clie‌​nt.py", it worked.
  • khalid13
    khalid13 about 11 years
    This isn't marked as correct, but I can verify that it works (as opposed to the answers below).
  • slamora
    slamora about 11 years
    Related post for debugging CA_BUNDLE used by python.
  • jfs
    jfs over 10 years
    @9emE0iL18gxCqLT: why do you think that all systems use the path you provided? requests can be packaged for your distribution. Run python -mrequests.certs to find out where it points to.
  • jfs
    jfs over 10 years
    @khalid13: An axe "works" as a headache medicine (no head - no headache). It doesn't mean that it is a good idea to use it that way. verify=False disables host's SSL certificate checking.
  • khalid13
    khalid13 over 10 years
    @J.F.Sebastian Honestly, it depends on what you're doing. For my quick/throwaway application, it was more than sufficient.
  • Matthias Urlichs
    Matthias Urlichs over 10 years
    If you have a self-signed certificate, then download it and set verify to its filename. There is no excuse whatsoever for setting verify=False. verify='/path/to/cert.pem'
  • Louis Cremen
    Louis Cremen almost 9 years
    Sorry Boud, I needed to down vote this answer as requests does not handle HTTPS requests "like a web browser". If the full SSL chain of trust (including intermediate certificates) is not declared on a server and requires an extra certificate download, you will receive the above SSL verification error. Web browsers will do the extra download and not flag any certificate errors. This is one way that a web browser and Requests differ. There are others. Requests does some verification, but it is not as good as a browser.
  • binki
    binki over 8 years
    @diyism making such a change sounds very unsafe…
  • CMCDragonkai
    CMCDragonkai over 8 years
    If the Python request's cacert bundle is out of date, how do I update it?
  • CMCDragonkai
    CMCDragonkai over 8 years
    What about replacing /usr/local/lib/python2.7/dist-packages/requests/cacert.pem with a symlink to the OS store?
  • Rafael Almeida
    Rafael Almeida over 8 years
    @diyism I agree completely with binki. What was the parameter before? True or a path?
  • Kenneth Reitz
    Kenneth Reitz over 8 years
    You shouldn't use that cacert.pem from curl. It contains many revoked certs. Check out Certifi (which Requests uses): certifi.io
  • Kenneth Reitz
    Kenneth Reitz over 8 years
    Note, this only applies to Requests installations via apt-get, which is modified by Debian/Ubuntu to use system certs. Requests proper ships with its own, carefully curated, CA bundle: certifi.io
  • alex-mcleod
    alex-mcleod about 8 years
    This did it for me. Thanks :)
  • jfs
    jfs about 8 years
    @KennethReitz: 1- what Requests uses fails for OP (otherwise there weren't be the question) 2- cacert.pem is CA certificates extracted from Mozilla (by cURL) -- it is just an example (if the CA list used by a popular web-browser can't be used as an example then I don't know what can be) -- the point of the answer that you can pass your own CA file if the default list fails.
  • dragon788
    dragon788 almost 8 years
    This has the downside of reinstalling potentially revoked/untrusted certificates from the older version of certifi, NOT recommended.
  • seans
    seans over 7 years
    if for some reason you're forced to stick with an early version of python 2.7, downgrading certifi is the only approach that worked for me
  • mallyvai
    mallyvai over 7 years
    This fixed my problem! I was using Charles Proxy on Mac to debug a library that made JSON calls to HTTPS APIs. I installed the Charless certificate as specified, added it to the keychain, but Python kept failing with: SSLError: ("bad handshake: Error([('SSL routines', 'ssl3_get_server_certificate', 'certificate verify failed')],)",) To fix this, I ended up following your advice about adding REQUESTS_CA_BUNDLE and exporting the Charles certificate from my keychain as a .pem file. Now, it works!
  • user565447
    user565447 over 7 years
    Thanks, the same issue was with opened Fiddler
  • Aamir Abro
    Aamir Abro over 7 years
    fixed by pip install -U requests[security] --no-cache two times and pip install certifi==2015.04.28
  • Tamás Szelei
    Tamás Szelei about 7 years
    FWIW, it's still present with requests==2.13.0. The above workaround fixes it still.
  • Howiecamp
    Howiecamp about 7 years
    @alanjds What if I want to either configure python to trust some ssl cert or to disable certificate verification but globally in the environment, without editing the source code? For example if I download existing Python utilities (eg the AWS CLI) and I want to trust certs or ignore certificate validation for those tools?
  • Howiecamp
    Howiecamp about 7 years
    @user565447 I'm trying to get this working with Fiddler right now. Should setting REQUESTS_CA_BUNDLE to Fiddler's cert work?
  • alanjds
    alanjds about 7 years
    @Howiecamp then you can go via j-f-sebastian answer, I guess: stackoverflow.com/a/12865159/798575
  • Howiecamp
    Howiecamp about 7 years
    @alanjds But doesn't his answer assume I'm writing the code and/or have access to the code? I'm looking to implement this at the environment level.
  • timmy
    timmy about 7 years
    Shouldn't the root CA be enough? Why do you need the intermediates?
  • davegallant
    davegallant about 7 years
    Oddly enough, I needed this on Python 2.7.6 but not 2.7.12.
  • Tim Ludwinski
    Tim Ludwinski almost 7 years
    If you updated OpenSSL to a version > 1.0.1, than that was probably the issue. See my answer bellow. stackoverflow.com/a/44543047/1413201
  • crazystick
    crazystick over 6 years
    Going from Python 2.7.9 to 2.7.10 fixed this for me.
  • Vincent Claes
    Vincent Claes over 6 years
    do pip install --upgrade pip before installing the requests security package to avoid other errors
  • Bagelstein
    Bagelstein about 6 years
    Where do you set the verify flag = false? All these comments saying to set it to false, none saying how....
  • Rafael Almeida
    Rafael Almeida about 6 years
    It’s a keyword argument to the get() function: requests.get('https://example.com', verify=False)
  • Coder Guy
    Coder Guy about 5 years
    Getting into the habit of accepting untrusted certificates completely negates the whole purpose of SSL. You'd be better off using a non-SSL endpoint. If your network repudiates SSL certificates wholesale it will be a hayday for attackers intercepting your network's traffic.
  • Rafael Almeida
    Rafael Almeida about 5 years
    That's a fair warning, and certainly the best course of action is to fix the reason the certificate is not being accepted. There are, however, quick/throwaway scenarios where this is not needed or even possible: you're crawling a website with a broken certificate, you're running automated tests in localhost with a self-signed certificate, etc.
  • user1156544
    user1156544 almost 5 years
    Can you do this and use client certificates at the same time? I'm getting problems with this.
  • jfs
    jfs almost 5 years
    @user1156544 client certificates seem unrelated to the answer (though I might be wrong, I didn't use client certificates in awhile)
  • user1156544
    user1156544 almost 5 years
    Yes, it is a different question. Just wanted to know if your answer could be applied in that situation
  • ghukill
    ghukill almost 5 years
    A hundred times this: key being inability to modify verify path.
  • user1114
    user1114 almost 5 years
    What if you're using a self signed cert? What would the CA be in that case?
  • user1114
    user1114 almost 5 years
    Tiny update - for python 3.6, there should be parentheses for the print command - python -c "import requests; print(requests.certs.where())"
  • find_all
    find_all over 4 years
    So does setting the verify parameter to a string that is the path of the .pem file of the certificate count as something that could legitimately be used in production? What is a fix for this one could use in production?
  • Rafael Almeida
    Rafael Almeida over 4 years
    If you trust that the .pem file is legit, and it’s stored in a place you trust not to be tampered, I would call using the .pem file a production-grade solution.
  • cowlinator
    cowlinator about 4 years
    For anyone wondering how to get multiple .pem certificates into your CA_BUNDLE file, they can just be appended to each other in the same file. Run python -c "import requests; print(requests.certs.where())", and open the printed filepath to see an example.
  • Lucas
    Lucas about 4 years
    I use a Python 2.7.10 installed by ArcGIS and there is no certifi module installed. The requests module installed is in version 2.11.1.
  • Taha Hamedani
    Taha Hamedani almost 4 years
    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?
  • Taha Hamedani
    Taha Hamedani almost 4 years
    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?
  • Ricky Levi
    Ricky Levi almost 4 years
    Yes, sometimes the problem is not with the code, the CERT really just doesn't match ... ( certs sometimes belong to a certain env etc .. )
  • Mubeen Shahid
    Mubeen Shahid over 2 years
    Thanks for the answer! The quick fix to use verify=False was the only possible solution in my scenario.
  • Naypa
    Naypa over 2 years
    requests uses the cert parameter to specify the certificate file, not verify: requests.get('https://example.com, verify=True, cert='./cert.pem')
  • jfs
    jfs over 2 years
    @never verify is correct here (CA path). Don't confuse with client certificate. See docs.python-requests.org/en/latest/user/advanced/…
  • Arnab Mukherjee
    Arnab Mukherjee over 2 years
    @LouisCremen Awesome comment. How to fix the issue via request. I mean download complete chain of certificates ?
  • W. Dan
    W. Dan about 2 years
    I'm CentOS7 OS, use REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-bundle.crt.
  • wxweven
    wxweven almost 2 years
    thanks a lot , pip install -U requests[security] helped me