在python 2.7.8到2.7.9的升级中,ssl模块从使用
_DEFAULT_CIPHERS = 'DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2'
到
_DEFAULT_CIPHERS = (
'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:'
'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:ECDH+RC4:'
'DH+RC4:RSA+RC4:!aNULL:!eNULL:!MD5'
)
我想知道这会如何影响在Windows上安装python时建立SSL/TLS连接时使用的实际“有序SSL密码首选项列表”。
例如,要确定密码列表扩展到什么“有序的SSL密码首选项列表”,我通常使用openssl ciphers
命令行(请参见man page),例如在openssl v1.0.1k中,我可以看到默认的python 2.7.8密码列表扩展到什么:
$ openssl ciphers -v 'DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2'
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA384
ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA384
ECDHE-RSA-AES256-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA1
ECDHE-ECDSA-AES256-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA1
SRP-DSS-AES-256-CBC-SHA SSLv3 Kx=SRP Au=DSS Enc=AES(256) Mac=SHA1
SRP-RSA-AES-256-CBC-SHA SSLv3 Kx=SRP Au=RSA Enc=AES(256) Mac=SHA1
...
snip!
当python在Linux上动态加载与openssl ciphers
使用的OpenSSL库时,这非常有用:
$ ldd /usr/lib/python2.7/lib-dynload/_ssl.x86_64-linux-gnu.so | grep libssl
libssl.so.1.0.0 => /lib/x86_64-linux-gnu/libssl.so.1.0.0 (0x00007ff75d6bf000)
$ ldd /usr/bin/openssl | grep libssl
libssl.so.1.0.0 => /lib/x86_64-linux-gnu/libssl.so.1.0.0 (0x00007fa48f0fe000)
但是,在Windows上,Python构建似乎静态地链接OpenSSL库。这意味着openssl ciphers
命令无法帮助我,因为它使用的库版本不同,它可能支持不同的密码,而不是内置在python中的库。
我可以很容易地找到OpenSSL的哪个版本用于构建这两个python版本:
$ python-2.7.8/python -c 'import ssl; print ssl.OPENSSL_VERSION'
OpenSSL 1.0.1h 5 Jun 2014
$ python-2.7.9/python -c 'import ssl; print ssl.OPENSSL_VERSION'
OpenSSL 1.0.1j 15 Oct 2014
但是,即使我可以找到并下载1.0.1h和1.0.1j版本的openssl
命令行的构建,我也不能确定它们的编译选项是否与python内置的lib相同,并且从man page中我们知道
Some compiled versions of OpenSSL may not include all the ciphers listed here because some ciphers were excluded at compile time.
那么,有没有办法让python的ssl模块提供类似于openssl ciphers -v
命令的输出?
Jan-Philip Gehrcke's answer需要尚未发布的python版本才有用(请参阅注释),这使得回答有关较旧版本python的问题变得不实际。但这一段启发了我:
这让我想到了一个可能的解决办法。都在同一个python程序中:
ciphers='ALL:aNULL:eNULL'
)。'DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2'
)'AES256-GCM-SHA384'
。客户端将从其配置的密码列表中选择与服务器提供的密码匹配的最高优先级密码。服务器接受任何密码,并使用相同的OpenSSL库在同一个python程序中运行,因此服务器的列表保证是客户机列表的超集。因此,使用的密码必须是提供给客户端套接字的扩展列表中优先级最高的密码。万岁。'DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2:!AES256-GCM-SHA384'
)下面是代码(也可用作a github gist):
请注意它默认如何测试python内置的默认密码列表:
因此,我们可以很容易地看到默认客户机密码列表扩展到什么,以及它如何从python 2.7.8更改为2.7.9:
我想这回答了我的问题。除非有人发现这种方法有问题?
您可能想在https://github.com/openssl/openssl/blob/master/apps/ciphers.c查看
openssl cipher
的源代码关键步骤似乎是:
meth = SSLv23_server_method();
ctx = SSL_CTX_new(meth);
SSL_CTX_set_cipher_list(ctx, ciphers)
,而ciphers
是字符串ssl = SSL_new(ctx);
sk = SSL_get1_supported_ciphers(ssl);
for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) { print SSL_CIPHER_get_name(sk_SSL_CIPHER_value(sk, i)); }
Python 3.4中的
SSL_CTX_set_cipher_list
函数在上下文的set_ciphers
方法中调用。您可以使用以下方法实现相同的目的:下一步是调用} 中没有使用它。最接近的是
SSL_get1_supported_ciphers()
,不幸的是,在Python的^{SSLSocket
实例的shared_ciphers()
方法。当前的实现是也就是说,这个循环与上面的
ciphers.c
实现非常相似,并返回密码的Python列表,其顺序与ciphers.c
中的循环相同。继续上面的
sslsock = SSLSocket(...)
示例,在连接套接字之前不能调用sslsock.shared_ciphers()
。否则,Python的ssl模块不会创建低级opensslsl对象,这是读取密码所必需的。这与ciphers.c
中的实现不同,后者创建一个低级SSL对象,而不需要连接。这就是我所取得的进展,我希望这能有所帮助,也许你可以根据这些发现找出你所需要的。
相关问题 更多 >
编程相关推荐