What causes SSLCertVerificationError, CERTIFICATE_VERIFY_FAIL when using Python on Windows? - python

If I do this:
import requests
url = 'https://us-street.api.smartystreets.com/i/redacted/the/url/because/its/an/api/call/with/private/info'
r = requests.get(url)
I get this:
SSLError: HTTPSConnectionPool(host='us-street.api.smartystreets.com', port=443): Max retries exceeded with url: /i/redacted/the/url/because/its/an/api/call/with/private/info (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1131)')))
However, when I put the URL directly into my Chrome browser, I get a response.

The key here is that the request works through the browser, so it's probably something limited to Python. Some sleuthing leads us to the following:
https://stackoverflow.com/a/65860355/5478086
The difference between the above post and our case is that our request still works when verify=False, so the problem is not on the server's side, but on our side. And so, we try the above answer
pip install python-certifi-win32
Or on Anaconda
conda install -c conda-forge python-certifi-win32
(h/t to iambr from this post.)
And now we can successfully make and verify requests from the above domain.

Related

Python Requests fails on a specific HTTPS site, although its certificate is valid

We're using a Python package that internally uses requests to access an online service. The service is located at https://dsbox02.isi.edu:8888/ . If you follow the link with your browser, you'll see that the page opens up, and that it has a valid certificate.
The following Python code, however, fails:
import requests
requests.get('https://dsbox02.isi.edu:8888')
requests.exceptions.SSLError: HTTPSConnectionPool(host='dsbox02.isi.edu', port=8888): Max retries exceeded with url: / (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1122)')))
This happens on Windows 10 and Python 3.7, Ubuntu 18.04 and Python 3.6 and the python:latest docker image, with Python 3.9. On a Mac with Python 3.8 it does work.
There are some ssl certificates that are not trusted in all web browsers. You may need to install an Intermediate/chain certificate to link it to a trusted root certificate.
The easiest way is to check your website with a ssl checker. Such as: https://www.sslshopper.com/ssl-checker.html#hostname=https://dsbox02.isi.edu:8888/

What's the most portable way to make python3 make insecure (e.g. 3DES, RC4) HTTPS requests?

for proper vulnerability scanning it's necessary that python3 speaks insecure HTTPS to avoid overlooking a vulnerable website just because openssl wouldn't talk to it because it was still using SSLv3 or 3DES. After all, those old servers mostly also have the vulnerable applications running on it ;) Compiling my own openssl with enable-weak-ciphers doesn't look like a good option because every user of the scanner also would have to do the same.
The OpenSSL 1.1.1 on my system wouldn't talk to these sites using python3 + requests:
10000-sans.badssl.com
3des.badssl.com
client.badssl.com
client-cert-missing.badssl.com
dh480.badssl.com
dh512.badssl.com
null.badssl.com
rc4.badssl.com
rc4-md5.badssl.com
subdomain.badssl.com
wrong.badssl.com
(I assume there's no way to get this done using requests and pyopenssl without recompiling openssl, so no need to post my code.)
Also this tip didn't work:
http://www.pybloggers.com/2017/02/configuring-tls-with-requests/
This throws this error: requests.exceptions.SSLError:
HTTPSConnectionPool(host='3des.badssl.com', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLError(1, '[SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure (_ssl.c:852)'),))
Any ideas on how to get it done without recompiling openssl?
thx
2d4d

RTC Python SSLv3

I am investigating if we can use IBM RTC API to create workitem, get workitem, etc using python scripting. I came across python library "rtcclient" which can achieve the required tasks however I am unable to use it since I get error as "SSLV3 Handshake Error" during the rtcclient call. I receive the same error even with requests.get function as well
requests.exceptions.SSLError: HTTPSConnectionPool(host='clm.demo.com', port=9443): Max retries exceeded with url: /jazz/authenticated/identity (Caused by SSLError(SSLError(1, u'[SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure (_ssl.c:726)'),))
I am able to retrieve the same details via cURL command however python still throws error. Below are my version details
IBM RTC CLM: 6.0.2
Python: 3.7.6
Libraries installed : cryptography, httplib2, pyopenssl, rtcclient, requests

Python Requests with wincertstore

I'm trying to connect to my corporate's internal webpages through the requests package, but since python does not use the windows default trusted certificates the connection is denied. I found out that wincertstore can be used to fetch the windows default certificates. But I'm still not sure how to use that along with the my request. Below is the code I have tried so far.............
import requests, socket, atexit, ssl, wincertstore
from requests.auth import HTTPBasicAuth
certfile = wincertstore.CertFile()
certfile.addstore("CA")
certfile.addstore("ROOT")
atexit.register(certfile.close)
ssl_sock = ssl.wrap_socket(s,ca_certs=certfile.name,
cert_reqs=ssl.CERT_REQUIRED)
requests.get(url)
I get the following error...................
requests.exceptions.SSLError: HTTPSConnectionPool(host='myhost', port=443): Max retries exceeded with url: myurl (Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')],)",),))
I am able to use wget on the same url and download the content.
wget --no check certificate --user=my username --password=my password URL
But I am not interested in downloading the content as I only need to scrape a small portion of the webpage content.
Pythin version = 3.6.5
Wincertstore link - Link
Thanks in advance for your help..............
I had a similar issue and fixed it using the python-certifi-win32 package (now out of maintenance):
As of 2022 (as mentioned by Briareos386 in the comments)
pip install pip-system-certs
Original answer (out of maintenance)
pip install python-certifi-win32
now you can just use:
requests.get(url, verify=True)
and the certificate is checked using the Windows Certificate Store.
Note:
This only works if the certificate is installed in the Windows Certificate Store...
This is all explained in the SSL Cert Verification section of the requests docs.
By default, requests uses the certs from certifi if present, falling back to whatever urllib3 thinks is your OS cert store, which itself falls back on whatever Python thinks it is (although in older versions it often didn't).
Your company apparently has a private, maybe even self-signed, cert, which isn't going to be in certifi. It might be in the Windows cert store—in which case urllib3 should automatically pick it up—but I suspect that it isn't. Maybe the cert is installed directly into some custom browser setup your IT department forces you to use, instead of into the OS store. Or maybe it's not installed at all. (You didn't mention being able to access this site in a browser without seeing a broken-lock icon…)
You're passing --no check certificate (or, more likely, --no-check-certificate?) to wget, so you're just not verifying SSL. And if you want to do the same thing in requests, that's just:
requests.get(url, verify=False)
If you're pretty sure that you do have the cert installed, even though wget can't find it… well, your code isn't going to work as written. Here's what would work:
Ignore the cert and just disable validation, as shown above.
Figure out where the relevant cert actually is installed and how to load it, and:
Pass it as the verify argument on every requests call.
Set it up somewhere statically and pass it in an environment variable.
Install it into your default cert store so everything works automatically.
Write an HTTPAdapter that installs it into your requests session.
First, your code is just trying to get the default cert in exactly the same way Python already does. That wincertstore module is just a backport of what's already builtin to Python 3.4+.
Second, all your code is doing is getting a cert, using it to create an SSL socket, ignoring that socket, and telling requests to do its normal thing. That isn't going to help anything. If you want to pass a cert to requests, you either do this:
requests.get(url, verify='/path/to/cert')
… or put it in the environment variable REQUESTS_CA_BUNDLE
… or do the HTTPAdapter code that I showed you in chat (and which you found an old, non-working version of somewhere unspecified). See HTTPAdapter in the docs if you actually want to do that.
In my case (Windows 10 + Python 3.10.2 + Elasticsearch 8.0.1)
When I ran the code below
requests.get('https://192.168.1.3:9200')
I got this error
Caused by SSLError(SSLCertVerificationError(1, '[SSL:
CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed
certificate in certificate chain (_ssl.c:997)')))
I tried previous solutions but none of them worked for me. I could fix the problem after adding Kibana's CA SSL certificate into Python's default certificate store.
Kibana's CA SSL can be found in your Kibana config file (kibana.yml > elasticsearch.ssl.certificateAuthorities)
Python's default certificate store can be found with this Python code
certifi.where()
Then copy the Kibana's CA certificate content and
paste it into the cacert.pem file.
Then it worked for me.

Django call https : [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed

I have to call a api(requests.post(https://192.168.16.10:8443/api/data,json=data)) in my django .
It's https ,so I install django-sslserver
to run django with https
But I got error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed
What else should I set??
I try to call https://192.168.16.10:8443/api/data directly by Postman , It works well.
It's the django problem
If you are using a self-signed certificate you can skip certificate verification:
requests.post("https://192.168.16.10:8443/api/data", verify=False)
See requests documentation on SSL verification for details.
Warning: This will reduce the security of SSL as #KlausD pointed out and should be used as a last resort.
you can use this command to skip this step
pip install djangorestframework --trusted-host=pypi.python.org --trusted-host=pypi.org --trusted-host=files.pythonhosted.org

Categories

Resources