Warm tip: This article is reproduced from serverfault.com, please click

Problem with Python requests SSLCertVerificationError

发布于 2020-11-28 14:49:48

I'm trying to figure out, why I'm having a problem that Python code is throwing a SSLCertVerificationError for valid LetsEncrypt certificates on a virtual host with multiple domains and certificates at the same IP If I delete all certificates except one it's fine, but with more than one certificate requests ignores the domain to which Python sent the request and pulls the most recent LetsEncrypt certificate, which is incorrect, causing the domain SSLCertVerificationError.

My understanding was that under SNI (Server Name Indication) requests should only pull the certificate for the domain to which the request is being made, not simply the most recent one. I have checked, and I'm running Python, 3.8, requests 2.5 under a version of Nginx that has been compiled with SNI support. I can suppress the error by turning off SSL validation, but that seems a poor workaround.

Any idea what is going on? Why does SNI work fine when browsers requests page from Nginx, pullign the proper certificate, but fail under when the same is done under Python's requests package? I have read everything I can find, and the docs say it should just work under the current builds of nginx, requests,OpenSSL, etc., but it clearly isn't here.


To replicate, I can do requests.get{'https://kedrosky.org') error-free from a local machine. But on scripts run at that server -- a hosted domain -- a newer certificate for the wrong domain is returned, causing an SSLCertVerificationError.

Questioner
Tim Benzedrine
Viewed
0
Steffen Ullrich 2020-11-29 01:26:15

The problem is that the server configuration is likely only properly done for IPv4 even though the domain also resolved to an IPv6 address. With IPv4 it returns the correct certificate:

 $ openssl s_client -connect kedrosky.org:443 -4
 ...
 subject=CN = kedrosky.com

But with IPv6 it returns a different certificate (this needs IPv6 connectivity to the internet on your local machine):

 $ openssl s_client -connect kedrosky.org:443 -6
 ...
 subject=CN = paulandhoward.com

Likely this is because there is only a listen 443 but not listen [::]:443, the latter needed for IPv6. In this case virtual hosts only properly work for IPv4 but with IPv6 it will just return the default, i.e. usually the first certificate configured.

And the reason that you are seeing different results from different hosts is that one has only IPv4 connectivity while the other can do IPv6 too.