在python ssl中,可以配置TLS客户端的密码套件和版本。密码套件使用context.set_ciphers(ciphers)
设置,版本使用context.options
设置。
为了确保从设置中,可以使用context.get_ciphers()
获取客户端中的密码(甚至在握手之前,这是用于设置客户端)。
我的问题:如何获得客户端支持的协议。请注意,我没有使用默认版本。我通过使用context.options
排除某些版本来更改它们。例如,此语句从我的客户端中排除了TLS 1.1:
context.options |= ssl.OP_NO_TLSv1_1
我想确保以与使用context.get_ciphers()
的密码相同的方式构建我的客户端TLS版本。我有什么方法可以这样做吗?
答案 0 :(得分:2)
Python 3 6 (和更新版本)中提供了您所追求的功能(至少部分)。查看[Python 3]: ssl - TLS/SSL wrapper for socket objects了解详情:
>>> import sys >>> import ssl >>> "Python {:s} on {:s}".format(sys.version, sys.platform) 'Python 3.6.5 (v3.6.5:f59c0932b4, Mar 28 2018, 17:00:18) [MSC v.1900 64 bit (AMD64)] on win32' >>> ctx0 = ssl.create_default_context() >>> ctx0.options <Options.OP_NO_SSLv3|OP_NO_SSLv2|OP_CIPHER_SERVER_PREFERENCE|OP_SINGLE_DH_USE|OP_SINGLE_ECDH_USE|OP_NO_COMPRESSION|OP_ALL: -2091252737>
对于旧版本,需要一些代码(也适用于较新的代码)。
code.py :
#!/usr/bin/python3
import sys
import ssl
from pprint import pprint as pp
__PROTO_TAG = "PROTOCOL_"
__OP_NO_TAG = "OP_NO_"
__OP_NO_TAG_LEN = len(__OP_NO_TAG)
_PROTOS_DATA = list()
for item_name in dir(ssl):
if item_name.startswith(__OP_NO_TAG) and item_name[-1].isdigit(): # item_name[-1].isdigit() condition is required because protocol denial (OP_NO_*) constants end in digit(s) (version); therefore constants like OP_NO_TICKET are excluded
op_no_item = getattr(ssl, item_name)
if op_no_item:
proto_name = item_name[__OP_NO_TAG_LEN:]
_PROTOS_DATA.append((proto_name, getattr(ssl, __PROTO_TAG + proto_name, -1), op_no_item))
del __OP_NO_TAG_LEN
del __OP_NO_TAG
del __PROTO_TAG
def get_protocols(ctx):
supported_classes = (ssl.SSLContext,)
if not isinstance(ctx, supported_classes):
raise TypeError("Argument must be an instance of `{:}`".format(supported_classes[0] if len(supported_classes) == 1 else supported_classes))
protocols = list()
for proto_data in _PROTOS_DATA:
if ctx.options & proto_data[-1] != proto_data[-1]:
protocols.append(proto_data[:-1])
return protocols
def print_data(ctx):
print("Options: {:08X} ({!r})".format(ctx.options, ctx.options))
print("Protocols:")
for proto in get_protocols(ctx):
print(" {:s} - {:d}".format(*proto))
print()
def main():
print("{:s}\n".format(ssl.OPENSSL_VERSION))
ctx0 = ssl.create_default_context()
print_data(ctx0)
print("--- Removing TLSv1_1...")
ctx0.options |= ssl.OP_NO_TLSv1_1
print_data(ctx0)
print("--- Adding SSLv3...")
ctx0.options -= ssl.OP_NO_SSLv3 # !!! N.B.: Due to the fact that ssl.OP_NO_* flags only have one bit set, this works, but DON'T DO IT !!!
print_data(ctx0)
print("\nComputed protocols:")
pp([item[:-1] + (hex(item[-1]),) for item in _PROTOS_DATA])
if __name__ == "__main__":
print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
main()
备注强>:
代码演练:
_PROTOS_DATA - 在模块导入时计算:它是基于 ssl 模块属性的协议条目列表。每个条目有3个字段:
为了清晰起见,它会在每次运行结束时显示
ssl.SSLContext
<强>输出强>:
赢取10 x64
e:\Work\Dev\StackOverflow\q049788677>"C:\Program Files (x86)\Microsoft Visual Studio\Shared\Python36_64\python.exe" code.py Python 3.6.5 (v3.6.5:f59c0932b4, Mar 28 2018, 17:00:18) [MSC v.1900 64 bit (AMD64)] on win32 OpenSSL 1.0.2k 26 Jan 2017 Options: -7CA5FC01 (<Options.OP_NO_SSLv3|OP_NO_SSLv2|OP_CIPHER_SERVER_PREFERENCE|OP_SINGLE_DH_USE|OP_SINGLE_ECDH_USE|OP_NO_COMPRESSION|OP_ALL: -2091252737>) Protocols: TLSv1 - 3 TLSv1_1 - 4 TLSv1_2 - 5 --- Removing TLSv1_1... Options: -6CA5FC01 (<Options.OP_NO_TLSv1_1|OP_NO_SSLv3|OP_NO_SSLv2|OP_CIPHER_SERVER_PREFERENCE|OP_SINGLE_DH_USE|OP_SINGLE_ECDH_USE|OP_NO_COMPRESSION|OP_ALL: -1822817281>) Protocols: TLSv1 - 3 TLSv1_2 - 5 --- Adding SSLv3... Options: -6EA5FC01 (<Options.OP_NO_TLSv1_1|OP_NO_SSLv2|OP_CIPHER_SERVER_PREFERENCE|OP_SINGLE_DH_USE|OP_SINGLE_ECDH_USE|OP_NO_COMPRESSION|OP_ALL: -1856371713>) Protocols: SSLv3 - 1 TLSv1 - 3 TLSv1_2 - 5 Computed protocols: [('SSLv2', -1, '0x1000000'), ('SSLv3', <_SSLMethod.PROTOCOL_SSLv3: 1>, '0x2000000'), ('TLSv1', <_SSLMethod.PROTOCOL_TLSv1: 3>, '0x4000000'), ('TLSv1_1', <_SSLMethod.PROTOCOL_TLSv1_1: 4>, '0x10000000'), ('TLSv1_2', <_SSLMethod.PROTOCOL_TLSv1_2: 5>, '0x8000000')] e:\Work\Dev\StackOverflow\q049788677>"e:\Work\Dev\VEnvs\py34x64_test\Scripts\python.exe" code.py Python 3.4.4 (v3.4.4:737efcadf5a6, Dec 20 2015, 20:20:57) [MSC v.1600 64 bit (AMD64)] on win32 OpenSSL 1.0.2d 9 Jul 2015 Options: -7CFDFC01 (-2097019905) Protocols: TLSv1 - 3 TLSv1_1 - 4 TLSv1_2 - 5 --- Removing TLSv1_1... Options: -6CFDFC01 (-1828584449) Protocols: TLSv1 - 3 TLSv1_2 - 5 --- Adding SSLv3... Options: -6EFDFC01 (-1862138881) Protocols: SSLv3 - 1 TLSv1 - 3 TLSv1_2 - 5 Computed protocols: [('SSLv2', 0, '0x1000000'), ('SSLv3', 1, '0x2000000'), ('TLSv1', 3, '0x4000000'), ('TLSv1_1', 4, '0x10000000'), ('TLSv1_2', 5, '0x8000000')] e:\Work\Dev\StackOverflow\q049788677>"c:\Install\x64\Python\Python\3.7\python.exe" code.py Python 3.7.0b4 (v3.7.0b4:eb96c37699, May 2 2018, 19:02:22) [MSC v.1913 64 bit (AMD64)] on win32 OpenSSL 1.1.0h 27 Mar 2018 Options: -7DBDFFAC (<Options.OP_NO_SSLv3|OP_CIPHER_SERVER_PREFERENCE|OP_NO_COMPRESSION|OP_ALL: -2109603756>) Protocols: TLSv1 - 3 TLSv1_1 - 4 TLSv1_2 - 5 --- Removing TLSv1_1... Options: -6DBDFFAC (<Options.OP_NO_TLSv1_1|OP_NO_SSLv3|OP_CIPHER_SERVER_PREFERENCE|OP_NO_COMPRESSION|OP_ALL: -1841168300>) Protocols: TLSv1 - 3 TLSv1_2 - 5 --- Adding SSLv3... Options: -6FBDFFAC (<Options.OP_NO_TLSv1_1|OP_CIPHER_SERVER_PREFERENCE|OP_NO_COMPRESSION|OP_ALL: -1874722732>) Protocols: SSLv3 - -1 TLSv1 - 3 TLSv1_2 - 5 Computed protocols: [('SSLv3', -1, '0x2000000'), ('TLSv1', <_SSLMethod.PROTOCOL_TLSv1: 3>, '0x4000000'), ('TLSv1_1', <_SSLMethod.PROTOCOL_TLSv1_1: 4>, '0x10000000'), ('TLSv1_2', <_SSLMethod.PROTOCOL_TLSv1_2: 5>, '0x8000000')]
OSX 9 x64 :
cfati@cfati-macosx9x64-1:~/Work/Dev/StackOverflow/q049788677]> python code.py Python 2.7.10 (default, Oct 14 2015, 05:51:29) [GCC 4.8.2] on darwin OpenSSL 1.0.1p-fips 9 Jul 2015 Options: 830203FF (2197947391L) Protocols: TLSv1 - 3 TLSv1_1 - 4 TLSv1_2 - 5 () --- Removing TLSv1_1... Options: 930203FF (2466382847L) Protocols: TLSv1 - 3 TLSv1_2 - 5 () --- Adding SSLv3... Options: 910203FF (2432828415L) Protocols: SSLv3 - 1 TLSv1 - 3 TLSv1_2 - 5 () Computed protocols: [('SSLv2', 0, '0x1000000'), ('SSLv3', 1, '0x2000000'), ('TLSv1', 3, '0x4000000'), ('TLSv1_1', 4, '0x10000000'), ('TLSv1_2', 5, '0x8000000')]
Ubtu 16 x64 :
[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q049788677]> python3 code.py Python 3.5.2 (default, Nov 23 2017, 16:37:01) [GCC 5.4.0 20160609] on linux OpenSSL 1.0.2g 1 Mar 2016 Options: 830203FF (2197947391) Protocols: TLSv1 - 3 TLSv1_1 - 4 TLSv1_2 - 5 --- Removing TLSv1_1... Options: 930203FF (2466382847) Protocols: TLSv1 - 3 TLSv1_2 - 5 --- Adding SSLv3... Options: 930203FF (2466382847) Protocols: TLSv1 - 3 TLSv1_2 - 5 Computed protocols: [('SSLv2', -1, '0x1000000'), ('SSLv3', -1, '0x2000000'), ('TLSv1', <_SSLMethod.PROTOCOL_TLSv1: 3>, '0x4000000'), ('TLSv1_1', <_SSLMethod.PROTOCOL_TLSv1_1: 4>, '0x10000000'), ('TLSv1_2', <_SSLMethod.PROTOCOL_TLSv1_2: 5>, '0x8000000')] [cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q049788677]> [cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q049788677]> LD_LIBRARY_PATH=../q049493537/Python-3.6.4:../q049320993/ssl/build/lib ../q049493537/Python-3.6.4/python code.py Python 3.6.4 (default, Mar 28 2018, 23:34:25) [GCC 5.4.0 20160609] on linux OpenSSL 1.0.2h-fips 3 May 2016 Options: 835A03FF (<Options.OP_ALL|OP_NO_SSLv3|OP_NO_SSLv2|OP_CIPHER_SERVER_PREFERENCE|OP_SINGLE_DH_USE|OP_SINGLE_ECDH_USE|OP_NO_COMPRESSION: 2203714559>) Protocols: TLSv1 - 3 TLSv1_1 - 4 TLSv1_2 - 5 --- Removing TLSv1_1... Options: 935A03FF (<Options.OP_ALL|OP_NO_TLSv1_1|OP_NO_SSLv3|OP_NO_SSLv2|OP_CIPHER_SERVER_PREFERENCE|OP_SINGLE_DH_USE|OP_SINGLE_ECDH_USE|OP_NO_COMPRESSION: 2472150015>) Protocols: TLSv1 - 3 TLSv1_2 - 5 --- Adding SSLv3... Options: 915A03FF (<Options.OP_ALL|OP_NO_TLSv1_1|OP_NO_SSLv2|OP_CIPHER_SERVER_PREFERENCE|OP_SINGLE_DH_USE|OP_SINGLE_ECDH_USE|OP_NO_COMPRESSION: 2438595583>) Protocols: SSLv3 - -1 TLSv1 - 3 TLSv1_2 - 5 Computed protocols: [('SSLv2', -1, '0x1000000'), ('SSLv3', -1, '0x2000000'), ('TLSv1', <_SSLMethod.PROTOCOL_TLSv1: 3>, '0x4000000'), ('TLSv1_1', <_SSLMethod.PROTOCOL_TLSv1_1: 4>, '0x10000000'), ('TLSv1_2', <_SSLMethod.PROTOCOL_TLSv1_2: 5>, '0x8000000')]