你好。 我正在尝试使用 https 连接到服务器。 我的证书是一个自签名证书,它包含在验证参数中,但结果是错误“证书验证失败”错误。 我怀疑这与自签名的证书(由 Microsoft IIS)有关,但使用 curl 可以。
提前致谢!
这是 openssl 输出:
openssl s_client -showcerts -connect server:44300
CONNECTED(00000003)
depth=0 CN = server
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 CN = server
verify error:num=21:unable to verify the first certificate
verify return:1
---
Certificate chain
0 s:/CN=server
i:/CN=server
-----BEGIN CERTIFICATE-----
<certificate data here>
-----END CERTIFICATE-----
---
Server certificate
subject=/CN=server
issuer=/CN=server
---
No client certificate CA names sent
Peer signing digest: SHA1
Server Temp Key: ECDH, P-256, 256 bits
---
SSL handshake has read 1477 bytes and written 431 bytes
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES256-GCM-SHA384
Session-ID: CC4A000083B1E03B446416C9C0B16CBEAB79949E3CF5C936A309A6F92FA01364
Session-ID-ctx:
Master-Key: 798A570B0EC2A0CBB7C4C4DE6167E7579A92239942D869CD794B8BEBEA6EB5E492394634AD32665A8BB829DE1F3858D2
Key-Arg : None
PSK identity: None
PSK identity hint: None
SRP username: None
Start Time: 1510329948
Timeout : 300 (sec)
Verify return code: 21 (unable to verify the first certificate)
---
我期待,因为证书在验证参数中,连接不会失败。 如果我在 python 之外尝试使用 curl ,它可以工作:
curl https://server:44300 --cacert /usr/share/ca-certificates/server.crt
HTTP/1.1 403 Forbidden
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Content-Length: 1158
Content-Type: text/html
Server: Microsoft-IIS/10.0
X-Frame-Options: SAMEORIGIN
P3P: CP=None
Access-Control-Allow-Methods: GET,POST,PUT,DELETE,OPTIONS
Access-Control-Allow-Headers: X-Requested-With,Content-Type
Access-Control-Allow-Credentials: true
Date: Fri, 10 Nov 2017 16:02:26 GMT
(它失败但不是因为证书问题)
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "xxxxx/TestVirtualEnv/local/lib/python2.7/site-packages/requests/api.py", line 72, in get
return request('get', url, params=params, **kwargs)
File "xxxxx/TestVirtualEnv/local/lib/python2.7/site-packages/requests/api.py", line 58, in request
return session.request(method=method, url=url, **kwargs)
File "xxxxx/TestVirtualEnv/local/lib/python2.7/site-packages/requests/sessions.py", line 508, in request
resp = self.send(prep, **send_kwargs)
File "xxxxx/TestVirtualEnv/local/lib/python2.7/site-packages/requests/sessions.py", line 618, in send
r = adapter.send(request, **kwargs)
File "xxxxx/TestVirtualEnv/local/lib/python2.7/site-packages/requests/adapters.py", line 506, in send
raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='nlybstqvp4nb75n.code1.emi.philips.com', port=44300): Max retries exceeded with url: / (Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')],)",),))
import requests
requests.get('https://server:44300', verify='/usr/share/ca-certificates/server.crt')
$ python -m requests.help
{
"chardet": {
"version": "3.0.4"
},
"cryptography": {
"version": "2.1.3"
},
"idna": {
"version": "2.6"
},
"implementation": {
"name": "CPython",
"version": "2.7.12"
},
"platform": {
"release": "4.10.0-38-generic",
"system": "Linux"
},
"pyOpenSSL": {
"openssl_version": "1010007f",
"version": "17.3.0"
},
"requests": {
"version": "2.18.4"
},
"system_ssl": {
"version": "1000207f"
},
"urllib3": {
"version": "1.22"
},
"using_pyopenssl": true
}
此命令仅适用于 Requests v2.16.4 及更高版本。 否则,
请提供有关您的系统的一些基本信息(Python 版本,
操作系统等)。
顺便说一句,这是 Ubuntu 16.04
这个错误几乎可以肯定是因为证书本身在某种程度上是无效的。 你能提供 PEM 编码的证书本身吗?
你好。 感谢你及时的答复。 这是证书:
-----开始证书-----
MIID3TCCAsWgAwIBAgIIU/nMdlbWojMwDQYJKoZIhvcNAQELBQAwMDEuMCwGA1UE
AwwlTkxZQlNUUVZQNE5CNzVOLmNvZGUxLmVtaS5waGlsaXBzLmNvbTAeFw0xNzEx
MTAwMDAwMDBaFw0yNzExMTAwMDAwMDBaMDAxLjAsBgNVBAMMJU5MWUJTVFFWUDRO
Qjc1Ti5jb2RlMS5lbWkucGhpbGlwcy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB
DwAwggEKAoIBAQC3mzWep6k1/FbkzzoyZ8QBy/tE8adfwKvw80zaLL+car1bBZ9U
VIXs4es3babtjD3QJWP5/mwoBdIp8gvQkjA1X7RBNJZXbPz6hGR4eqaeRQLrFV9Y
TtB92MA9CDpCXfalCvzzO1jw3zvP1BHUdnTQEwSnnwtf/Ryaud+e7TDxGq8LThmc
glZgO8d2zaYpIjwWx92bXDF/qlqWBkH5mtKIkWOw6Y71xz0Di62cFrMAPEGBjK3c
szpBa5Ttb9+SFtl16t2xDyCbiPFkoMW/4u3Husy/i18hLhEuQwZMHnWsocm+etZ4
8fDt5Bqhab8zC+LKS+Ll7qZdqMHzobeB6j5JAgMBAAGjgfowgfcwXwYDVR0jBFgw
VoAUGdJ3os9nPtTubuwcy1ugtDMdSMChNKQyMDAxLjAsBgNVBAMMJU5MWUJTVFFW
UDROQjc1Ti5jb2RlMS5lbWkucGhpbGlwcy5jb22CCFP5zHZW1qIzMB0GA1UdDgQW
BBQZ0neiz2c+1O5u7BzLW6C0Mx1IwDAMBgNVHRMBAf8EAjAAMAsGA1UdDwQEAwIE
sDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwOwYDVR0RBDQwMoIlTkxZ
QlNUUVZQNE5CNzVOLmNvZGUxLmVtaS5waGlsaXBzLmNvbYIJbG9jYWxob3N0MA0G
CSqGSIb3DQEBCwUAA4IBAQC0MtflowNB4LTLKD1MW3w0QIY5ale3/sEhNCQgHGN5
iNZJptFuFt5jgPGmFjy0Pb5vLMS/Ag1RF3UgTeZzFnaSgyB4mTnwj1gLdwQidVcr
2SlL7TffCj0m/bYjtNbwExRqXE4pQKb5RKwYwpruZaX/G3oHWOG9+2X9Pw5C42zB
OFE4KvYUwOV+noabXvil8LERIdKYxR/2B6qBiwm47IcioqM07zTYLHJ+WDTEMO2k
Qy51yXwFmeOer5MIBElYCQ0j2AfI4RCXr+2cyUym7tjEr3/I8EsZ5Crvdf++Gwaz
2A05ScPMr+5yfVXygZCenMTwNAyUY1yN9zVj8/n94Psa
-----结束证书-----
我知道并不完全有效。 但不知何故 curl 能够接受它。 我想知道为什么 requests 不这样做。 我假设两者都使用 openssl 来验证证书。
对此有何更新? 我还面临 python 请求库中自签名认证站点的问题。
低于错误。
requests.get('https://10.10.24.20', verify='/etc/ssl/certs/certSIGN_ROOT_CA.pem')
回溯(最近一次通话最后):
文件 ”",第 1 行,在
文件“/usr/local/lib/python2.7/dist-packages/requests/api.py”,第 72 行,在 get
返回请求('get',url,params=params, *kwargs)文件“/usr/local/lib/python2.7/dist-packages/requests/api.py”,第 58 行,在请求中返回 session.request(method=method, url=url, * kwargs)
文件“/usr/local/lib/python2.7/dist-packages/requests/sessions.py”,第 508 行,在请求中
resp = self.send(prep, *send_kwargs)文件“/usr/local/lib/python2.7/dist-packages/requests/sessions.py”,第 618 行,在发送中r = adapter.send(request, * kwargs)
文件“/usr/local/lib/python2.7/dist-packages/requests/adapters.py”,第 506 行,在发送中
引发 SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='10.10.24.20', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'tls_process_server_certificate ', '证书验证失败')],)",),))
如果我保持 verify False 它可以工作,但我希望它带有 verify=True
之前没有看到这个,所以我开了一个新问题,对此感到抱歉。 但我面临同样的问题。 对我来说,即使验证 = False,“请求”也会失败。
$蟒蛇
Python 2.7.13(默认,2017 年 1 月 19 日,14:48:08)
[GCC 6.3.0 20170118] 在 linux2 上
输入“帮助”、“版权”、“信用”或“许可”以获取更多信息。
导入请求
requests.get("https://localhost:9000/getcpuinfo", verify=False)
回溯(最近一次通话最后):
文件 ”",第 1 行,在
文件“/usr/lib/python2.7/dist-packages/requests/api.py”,第 70 行,在 get
返回请求('get',url,params=params, *kwargs)文件“/usr/lib/python2.7/dist-packages/requests/api.py”,第 56 行,在请求中返回 session.request(method=method, url=url, * kwargs)
请求中的文件“/usr/lib/python2.7/dist-packages/requests/sessions.py”,第 488 行
resp = self.send(prep, *send_kwargs)文件“/usr/lib/python2.7/dist-packages/requests/sessions.py”,第 609 行,在发送中r = adapter.send(request, * kwargs)
发送中的文件“/usr/lib/python2.7/dist-packages/requests/adapters.py”,第 497 行
引发 SSLError(e, request=request)
requests.exceptions.SSLError: ("糟糕的握手: SysCallError(-1, 'Unexpected EOF')",)
我的本地证书信息是,
$ openssl s_client -showcerts -connect localhost:9000
CONNECTED(00000003)
depth=0 CN = localhost
verify error:num=18:self signed certificate
verify return:1
depth=0 CN = localhost
verify return:1
write:errno=0
---
Certificate chain
0 s:/CN=localhost
i:/CN=localhost
-----BEGIN CERTIFICATE-----
MIIC/jCCAeagAwIBAgIJAKATu2AY/QT4MA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
BAMMCWxvY2FsaG9zdDAeFw0xNzExMDkyMTQ1NTBaFw0xNzEyMDkyMTQ1NTBaMBQx
EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAJTPk5nao0wG/EDFGnq7BvXMkEZ5oUVq7PAUxWi+E/byJk924l7Z5kACgWBa
zQL0lLXLpdMk97EFGWMblz5Ehtqh7U8HaE9OZ6x/pesDTka+REnpXecklRrdZHX7
lfFnNIU58grPpB2GyUXrRdOtcPlaKXUo+VTd7PgwMtYVtt8pyTWxSB2MMYrqJGT8
78KX6trRzQLm7tas3U0jD59+R8j7gxU6FyFaNJBrkJ5T9kHGKOsAzSqZdCgRBjl5
i7xcXJfOAAnZ3jhGlY5DQht+HZDHhjkLG9kcZZhFDYteFk8drzbd3lBw96nLq+8A
Sy92FtQL4GiYSwZ0WVAmwmTCGjUCAwEAAaNTMFEwHQYDVR0OBBYEFLYjwGKbcV9h
sYHxe8l9UvXVivByMB8GA1UdIwQYMBaAFLYjwGKbcV9hsYHxe8l9UvXVivByMA8G
A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHl7okBCJlms+cwfzLhs
sbyyuX2wgngxyvjy497zBmeh1TiueGPhOx9u/sfJSZmoUaeRd/zPGkp2DcPQ+Lo2
EHYrXMPE1Ecgpu/15JZ8jNuE+FwZb9lllULLwzq8pDkdbdsSRltdV/rFlZ2YkscB
c+xvVaCltw5KpKnY6AWHoqwoDcd8TZKzyKXLSuluKbHNC1lvg8cMzs6hFA9P92Ae
9P08AKLAIOGJ7QzRrXQIsAO4p9rHheeZeYQZyNiRrXPQUoWos4+OjynaNs+FabhN
XBtSl/GGPRRRfU/D9v4iKfQx15CEvs1AKn1Z6mIPF05pSqbgIoz2mJBV6UM7e+hz
TRs=
-----END CERTIFICATE-----
---
Server certificate
subject=/CN=localhost
issuer=/CN=localhost
---
No client certificate CA names sent
Peer signing digest: SHA512
Server Temp Key: ECDH, P-256, 256 bits
---
SSL handshake has read 1198 bytes and written 302 bytes
Verification error: self signed certificate
---
New, TLSv1.2, Cipher is ECDHE-RSA-AES128-GCM-SHA256
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES128-GCM-SHA256
Session-ID:
Session-ID-ctx:
Master-Key: 5311B8500C8AF327083E1465FE1E1A6A98E0996B4791150A01D6B130C7F0549909A4BDCDED388E9EDE124BB6C50E150A
PSK identity: None
PSK identity hint: None
SRP username: None
Start Time: 1510599077
Timeout : 7200 (sec)
Verify return code: 18 (self signed certificate)
Extended master secret: no
---
请不要劫持这个问题。 一般来说,你应该使用 Stack Overflow 来问这些问题:如果你用请求来超载问题,你只会让我倾向于关闭它。
@sg77您的证书被标记CA=FALSE
,这使得它没有资格成为发行证书。 我怀疑 curl 正在自定义他们的代码以将此证书用作 pin,而不是作为根 CA。 Requests 不这样做:此证书不能是根 CA,因此它不会验证。
我建议使用CA=TRUE
创建一个新证书,或者完全省略 BasicConstraints。
@ashwini-kaklij 我不知道为什么您的验证失败,因为我看不到证书。 请不要在此处发布:将您的问题直接发送到 StackOverflow。
@uttampawar您的错误是由于服务器出于某种原因不喜欢我们的 TLS 握手引起的。 在没有更多细节的情况下,我无法确定原因。 请再次将您的问题提交给 Stack Overflow。
@Lukasa我并不是要劫持这个问题只是提升。 可能这是一个错误的地方。 我添加了我的评论和观察,因为我看到它具有相似的性质。 感谢您的反馈。 我会在stackoverflow上问。 谢谢。
请不要劫持这个问题。 一般来说,你应该使用 Stack Overflow 来问这些问题:如果你用请求来超载问题,你只会让我倾向于关闭它。
@sg77您的证书被标记
CA=FALSE
,这使得它没有资格成为发行证书。 我怀疑 curl 正在自定义他们的代码以将此证书用作 pin,而不是作为根 CA。 Requests 不这样做:此证书不能是根 CA,因此它不会验证。我建议使用
CA=TRUE
创建一个新证书,或者完全省略 BasicConstraints。@ashwini-kaklij 我不知道为什么您的验证失败,因为我看不到证书。 请_不要在此处发布_:将您的问题直接发送到 StackOverflow。
@uttampawar您的错误是由于服务器出于某种原因不喜欢我们的 TLS 握手引起的。 在没有更多细节的情况下,我无法确定原因。 请再次将您的问题提交给 Stack Overflow。
嗨 Lukasa - 刚刚看到你的回复。 您已回复@sg77说“您的证书标记CA=FALSE
”。
你如何判断这是错误的,我在哪里/如何将其设置回 TRUE?
谢谢。
在线发布证书密钥就像发布您的密码
@辛尼达
在线发布证书密钥就像发布您的密码
嗯,没有。 发布证书的私钥等同于您的密码。
每个业务中的 CA 在每个主流操作系统和浏览器中都有自己的证书。 他们是否将密码泄露给所有人?
这个错误几乎可以肯定是因为证书本身在某种程度上是无效的。 你能提供 PEM 编码的证书本身吗?
我怎样才能获得这个证书?
如果您是 python requests
模块的初学者并且想要做一些需要访问安全站点的事情,那么您很有可能会被这个错误注定 - Certificate verify failed
并且像所有初学者程序员一样会很想使用auth = session.post( mysecureurl, verify=false)
但这是非常糟糕的做法,并且在很多 SO 帖子中都被劝阻,但初学者仍然会滥用它,因为这个错误很难修复。
让我尝试对这个问题进行一些说明。
Python(pip) 和 Conda 以及任何基于 python 的软件都使用单独的证书存储,就像所有浏览器一样。 Python Requests 库默认使用它自己的 CA 文件,或者如果安装了 certifi 包的证书包,将使用它。 此外,与curl
不同,pip 不使用系统证书。
因此,对于requests
,您必须通过 conda 或 pip 手动指定证书存储。
特长;
.cer
编码的证书链。 请注意,该博客不是关于 conda certstore 而是 git certstore ,它只说导出根目录,但是我将所有证书链导出到单独的文件中。pip install certifi
安装certifi
#$import ssl
ssl.get_default_verify_paths()
或import certifi
certifi.where()
找到默认的cacert.pem
文件后,打开它(最好在 Notepad++ 中)并在文件末尾附加所有证书。 (注意证书划分-----BEGIN CERTIFICATE-----
和-----END CERTIFICATE-----
)。 保存文件,就是这样。
或者,如果您使用 conda,请使用 conda 命令:
conda config --set ssl_verify <pathToYourFile>.crt
(我注意到这个命令会更新C:\Users\johndoe\.condarc
中的内容)
使用以下代码进行验证:
import certifi
auth = session.post('https://mysecuresite.com/', cert=());
此外,如果您使用的是 linux,则可以使用此链接将自定义 cacert 导出到系统范围或用户配置文件( .bashrc
或.bash_profile
)。
最有用的评论
如果您是 python
requests
模块的初学者并且想要做一些需要访问安全站点的事情,那么您很有可能会被这个错误注定 -Certificate verify failed
并且像所有初学者程序员一样会很想使用auth = session.post( mysecureurl, verify=false)
但这是非常糟糕的做法,并且在很多 SO 帖子中都被劝阻,但初学者仍然会滥用它,因为这个错误很难修复。
让我尝试对这个问题进行一些说明。
Python(pip) 和 Conda 以及任何基于 python 的软件都使用单独的证书存储,就像所有浏览器一样。 Python Requests 库默认使用它自己的 CA 文件,或者如果安装了 certifi 包的证书包,将使用它。 此外,与
curl
不同,pip 不使用系统证书。因此,对于
requests
,您必须通过 conda 或 pip 手动指定证书存储。特长;
.cer
编码的证书链。 请注意,该博客不是关于 conda certstore 而是 git certstore ,它只说导出根目录,但是我将所有证书链导出到单独的文件中。pip install certifi
安装certifi
#$import ssl
ssl.get_default_verify_paths()
或import certifi
certifi.where()
找到默认的
cacert.pem
文件后,打开它(最好在 Notepad++ 中)并在文件末尾附加所有证书。 (注意证书划分-----BEGIN CERTIFICATE-----
和-----END CERTIFICATE-----
)。 保存文件,就是这样。或者,如果您使用 conda,请使用 conda 命令:
conda config --set ssl_verify <pathToYourFile>.crt
(我注意到这个命令会更新
C:\Users\johndoe\.condarc
中的内容)使用以下代码进行验证:
import certifi
auth = session.post('https://mysecuresite.com/', cert=());
此外,如果您使用的是 linux,则可以使用此链接将自定义 cacert 导出到系统范围或用户配置文件(
.bashrc
或.bash_profile
)。