【问题标题】:SSL client certificate is not sent by python 'requests' library or s_client, but works fine in web browsersSSL 客户端证书不是由 python 'requests' 库或 s_client 发送的,但在 Web 浏览器中可以正常工作
【发布时间】:2014-08-29 14:21:11
【问题描述】:

我正在尝试用 Python 编写一个客户端脚本来访问 Web 应用程序并使用 SSL 客户端证书进行身份验证。尽管只要我加载了客户端证书,我就可以从 Firefox 和 Chrome 访问该应用程序,但每当我通过 Python 'requests 发送请求时,我都会收到以下响应:

400 No required SSL certificate was sent
nginx/1.4.6 (Ubuntu)

我也尝试过 Python httplib、s_client 和 curl,并得到相同的错误消息。我对所有测试使用相同的客户端证书,以 pkcs12 格式用于 Web 浏览器,并为命令行工具提取证书和密钥 PEM 文件。我的python代码如下:

import requests

CERT = r'/path/to/cert.crt' #Client certificate
KEY = r'/path/to/key.key' #Client private key
CACERT = r'/path/to/ca.crt' #Server certificate chain

session = requests.Session()
session.cert = (CERT, KEY)
resp = session.get('https://my.webapp.com/',
                   verify=CACERT)

print resp.content
session.close()

s_client 提供有关正在发生的事情的更多信息。这是输出的缩写版本:

$ openssl s_client -cert cert.crt -key key.key -CAfile ca.crt -connect <host>:<port>
CONNECTED(00000003)
depth=2 /C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
verify return:1
depth=1 /C=US/O=GeoTrust, Inc./CN=RapidSSL CA
verify return:1
depth=0 /serialNumber=tgBIwyM-p18O/aDyvyWNKHDnOezzDJag/OU=GT89519184/OU=See www.rapidssl.com/resources/cps (c)13/OU=Domain Control Validated - RapidSSL(R)/CN=*.rexdb.us
verify return:1
---
Certificate chain
...
---
Server certificate 
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
subject=...
---
No client certificate CA names sent
---
SSL handshake has read 3519 bytes and written 328 bytes
---
New, TLSv1/SSLv3, Cipher is DHE-RSA-AES128-SHA
Server public key is 4096 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1
    Cipher    : DHE-RSA-AES128-SHA
    Session-ID: ...
    Session-ID-ctx:
    Master-Key: ...
    Key-Arg   : None
    Start Time: 1409269239
    Timeout   : 300 (sec)
    Verify return code: 0 (ok)
---
GET / HTTP/1.1
Host: my.webapp.com

HTTP/1.1 400 Bad Request
Server: nginx/1.4.6 (Ubuntu)
Date: Thu, 28 Aug 2014 23:41:04 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: close
...
<head><title>400 No required SSL certificate was sent</title></head>
...
closed

我有理由确定这不是服务器的问题,因为身份验证在浏览器中有效。但是,s_client 输出显示“未发送客户端证书 CA 名称”,这听起来像是服务器问题(例如,客户端证书没有发送到服务器,因为服务器没有要求它)。下面是nginx配置的相关部分:

ssl                  on;
ssl_certificate_key  /path/to/server/key.pem;
ssl_certificate      /path/to/server/certificate.pem;
ssl_protocols        TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:AES128:AES256:RC4-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK;
ssl_prefer_server_ciphers   on;
ssl_session_timeout  5m;

ssl_client_certificate /path/to/client/ca/certificate.crt;
ssl_verify_depth 10;
ssl_verify_client on;

应用程序通过 nginx 使用 uwsgi。 vm上有多个虚拟主机,只有这一个使用证书认证。

我能找到的唯一其他可能相关的区别是,在 Firefox 中连接是保持活动的,而在 s_client 中它是关闭的。我尝试在标题中设置 Connection: keep-alive,结果相同。

【问题讨论】:

    标签: python ssl nginx https client-certificates


    【解决方案1】:

    vm上有多个虚拟主机,只有这一个使用证书认证。

    我假设这意味着您在同一个 IP 地址后面有多个证书,并且客户端必须使用 SNI(服务器名称指示)在 SSL 握手中向服务器发送预期的主机名。 openssl s_client 默认不使用 SNI,我不知道 python 是否使用 - 这可能取决于您使用的 python 版本。

    因为客户端仅在服务器告诉它这样做时才发送证书,因此由于缺少 SNI,您会遇到错误的配置部分,即带有另一个证书的默认部分,并且不需要客户端证书。

    我建议再次尝试使用openssl s_client,但使用命令行选项-servername(未在手册页中记录,但在使用-h 调用时显示)显式设置预期的服务器名称。如果这可行,您也需要找到一种在 python 中使用 SNI 的方法。如果这不起作用,请进行数据包转储并使用wireshark确保服务器确实需要客户端发送证书而客户端确实不发送证书。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-02
    • 1970-01-01
    • 2017-10-18
    • 2013-06-16
    • 2014-10-01
    • 1970-01-01
    • 2020-01-14
    相关资源
    最近更新 更多