更改Python使用的TLS版本

更改Python使用的TLS版本,python,ssl,Python,Ssl,我想连接一个服务,其所有者告诉我需要连接TLS 1.2 问题是我的Python使用TLS1.3 我用python-c import-requests命令检查了它;打印请求,获取'https://www.howsmyssl.com/a/check,verify=False.json['tls_version'] 是否有可能将TLS降到1.2?那么 第一 你应该知道ssl或者现在称为tls,是一个握手同意对方的过程,首先打开TCP套接字,然后通过该套接字的通信将被隐藏加密,或者你可以用wiresha

我想连接一个服务,其所有者告诉我需要连接TLS 1.2

问题是我的Python使用TLS1.3 我用python-c import-requests命令检查了它;打印请求,获取'https://www.howsmyssl.com/a/check,verify=False.json['tls_version']

是否有可能将TLS降到1.2?

那么

第一 你应该知道ssl或者现在称为tls,是一个握手同意对方的过程,首先打开TCP套接字,然后通过该套接字的通信将被隐藏加密,或者你可以用wireshark嗅探,由于使用python或其他语言时使用的通常方法是对套接字进行包装,我的意思是,只是一个中间类为您进行加密,而您甚至不关心,最后,客户机和服务器之间使用的共享加密套件在前面提到的握手过程中达成了一致

第二 HTTP只是TCP上的另一个应用层,但真正的测试将始终在传输层上进行,我将在下一行分享我自己的tls/ssl程序测试仪,以减少理论缺陷

您可以像python3.x.exe program.py-ip-443一样运行它,但是您应该在这个program.py旁边放置两个文件,local.crt和local.key文件作为我的程序的默认文件,但是您可以始终使用选项-tls../location/other.crt../location/other.key指定它们

使用local.crt和local.key的原因基本上是握手是交换密钥local.xxx文件和远程服务器文件的过程,因此在我的下一个测试程序示例中,我总是基于这些local.xxx文件定制ssl上下文变量,请注意上面使用的.load\u cert\u链

无论如何,您可以使用openssl命令非常轻松地生成它们,如openssl req-newkey rsa:2048-new-x509-nodes-days 3650-keyout-llave.key-out cert.crt-subc/C=CO/ST=ANT/L=Medellin/O=YourCompany/OU=YourArea/CN=YourDevice/emailAddress=joseveland@gmail.com或者类似于只将它们保存在单独的.crt和.key文件中的网站你的

import os, platform, socket, ssl
if platform.system().lower() == 'linux':    # Linux OS ..
    windows = False
    slash_principal = '/'
    slash_secundario = '\\'
    limpiar_pantalla = lambda :os.system('clear')
else:   # Windows OS ..
    windows = True
    slash_principal = '\\'
    slash_secundario = '/'
    limpiar_pantalla = lambda :os.system('cls')

import argparse, errno
limpiar_pantalla()
filepath = os.path.dirname(os.path.abspath(__file__))
ssl_files_def = [filepath+slash_principal+'local.crt', filepath+slash_principal+'local.key']

parser = argparse.ArgumentParser( description="Probador de TLS")
parser.add_argument( '-ip', nargs=1, metavar='IP', default=['www.google.com'], type=str, help=' IP del socket TCP a probar')    # 34.196.130.67 EPSA Pruebas
parser.add_argument( '-puerto', nargs=1, metavar='PUERTO', default=[443], type=int, help=' Puerto del socket TCP a probar')
parser.add_argument( '-version', nargs=1, metavar='TLS_VERSION', type=int, choices=[0,1,2,3], help=' Version TLS a probar si no se especifica se hara AUTO')
parser.add_argument( '-tls', nargs=2, metavar=('CRT', 'KEY'), default=ssl_files_def, type=str, help=' Ruta al archivo ".crt" ..y.. ruta al archivo ".key" locales, para ejecutar el handshake/intercambio TLS con alguien remoto')
parser_opts = parser.parse_args()
#print("Argumentos -->", parser_opts._get_kwargs())
#print()


# ---------------- Logica ---------------- #

sock_pair = ( parser_opts.ip[0], parser_opts.puerto[0] )
sock_tls_ver = ssl.PROTOCOL_TLS     # Auto
if parser_opts.version:             # Se ingreso en el parse? (!= None) ya que no es obligatoria
    if parser_opts.version[0] == 0:
        sock_tls_ver = ssl.PROTOCOL_TLSv1
    elif parser_opts.version[0] == 1:
        sock_tls_ver = ssl.PROTOCOL_TLSv1_1
    elif parser_opts.version[0] == 2:
        sock_tls_ver = ssl.PROTOCOL_TLSv1_2
    #elif parser_opts.version[0] == 3:
    #   sock_tls_ver = ssl.PROTOCOL_TLSv1_3

sslCntx = ssl.SSLContext(sock_tls_ver)  # https://docs.python.org/3/library/ssl.html#ssl.SSLContext
# Con las siguientes opciones se evitan suites SSL inseguras (Al final solo permitira >= TLSv1..)
sslCntx.options |= ssl.OP_NO_SSLv2
sslCntx.options |= ssl.OP_NO_SSLv3
if parser_opts.version:             # Se ingreso en el parse? (!= None) ya que no es obligatoria
    if parser_opts.version[0] >= 1:
        sslCntx.options |= ssl.OP_NO_TLSv1      # Evite la version 0 de TLS al conectar/handshake (version >= v1.1) 
    if parser_opts.version[0] >= 2:
        sslCntx.options |= ssl.OP_NO_TLSv1_1    # Evite la version 1 de TLS al conectar/handshake (version >= v1.2) 
    if parser_opts.version[0] >= 3:
        sslCntx.options |= ssl.OP_NO_TLSv1_2    # Evite la version 2 de TLS al conectar/handshake (version >= v1.3)
sslCntx.load_cert_chain(*ssl_files_def)         # Finalmente cargue mis llaves con las que hare el handshake.

print()
print('Versiones SSL (Obsoleto, demostrativo):', int(ssl.PROTOCOL_SSLv23))  # OBSOLETO HACE RATO.
print('Versiones TLS:', int(ssl.PROTOCOL_TLSv1), int(ssl.PROTOCOL_TLSv1_1), int(ssl.PROTOCOL_TLSv1_2))#, ssl.PROTOCOL_TLSv1_3)
print('Mi Contexto:', sslCntx.options, int(sslCntx.minimum_version), int(sslCntx.maximum_version), sslCntx.verify_flags, sslCntx.verify_mode, sslCntx.get_ca_certs())#, sslCntx.get_ciphers(), dir(sslCntx))
print('Remoto:', sock_pair)
print()

s = socket.socket()
s_tls = sslCntx.wrap_socket(s)  # Wrap lo convierte en un socket que hara handshake TLS y la comunicacion sera encriptada por ello.
try:
    print('Socket Ok:', s_tls.version(), s_tls.session, s_tls.shared_ciphers() )#, dir(s_tls))
    print()
    s_tls.connect(sock_pair)
    
    print('Conexion Ok:', s_tls.version(), s_tls.session.timeout)
    print( s_tls.shared_ciphers() )#, dir(s_tls.session), dir(s_tls))
    print()
    s_tls.close()

except socket.error as e:
    print('Socket FALLO (', os.strerror(e.errno), ')')

except Exception as e:
    print('Conexion FALLO:', type(e).__name__, e)

print()
注意:此程序还可用于测试您想要的任何套接字/页面,并将tls版本指定为选项-version 0、-version 1、-version 2、-version 3以强制特定的tls版本,并可用于检测可降级的不安全服务器

第三 概念很清楚,如果您已经想通过应用层python模块测试TLS,那么您需要将前面代码的这个自定义sslCntx ssl上下文变量放在或指定在这个所需的模块上,以便它可以根据它的文档而变化

我的意思是替换这个

s = socket.socket()
s_tls = sslCntx.wrap_socket(s)  # Wrap lo convierte en un socket que hara handshake TLS y la comunicacion sera encriptada por ello.
try:
    print('Socket Ok:', s_tls.session, s_tls.version(), s_tls.shared_ciphers(), s_tls )#, dir(s_tls))
    print()
    s_tls.connect(sock_pair)
    
    print('Conexion Ok:', s_tls.session.timeout, s_tls.version(), s_tls.shared_ciphers(), s_tls )#, dir(s_tls.session), dir(s_tls))
    print()
    s_tls.close()
from http.client import HTTPSConnection
try:
    conn = HTTPSConnection(*sock_pair, context=sslCntx)
    print('HTTP Ok:', conn.host, conn.port)#, dir(conn))
    print()
    conn.request( 'GET', '/' )
    ans = conn.getresponse()
    print('GET', ans.reason, ':', ans.status)
    print(ans.headers)#, dir(ans))
    conn.close()
    print()
。。。根据所需模块的具体情况,例如http模块上的参数上下文如下所示

s = socket.socket()
s_tls = sslCntx.wrap_socket(s)  # Wrap lo convierte en un socket que hara handshake TLS y la comunicacion sera encriptada por ello.
try:
    print('Socket Ok:', s_tls.session, s_tls.version(), s_tls.shared_ciphers(), s_tls )#, dir(s_tls))
    print()
    s_tls.connect(sock_pair)
    
    print('Conexion Ok:', s_tls.session.timeout, s_tls.version(), s_tls.shared_ciphers(), s_tls )#, dir(s_tls.session), dir(s_tls))
    print()
    s_tls.close()
from http.client import HTTPSConnection
try:
    conn = HTTPSConnection(*sock_pair, context=sslCntx)
    print('HTTP Ok:', conn.host, conn.port)#, dir(conn))
    print()
    conn.request( 'GET', '/' )
    ans = conn.getresponse()
    print('GET', ans.reason, ':', ans.status)
    print(ans.headers)#, dir(ans))
    conn.close()
    print()
并像python3.x.exe program.py-ip-puerto 443-version 2一样运行它,因为在您提出的问题上,您要求强制使用TLSv1.2

第四 另一方面,当不使用-version选项时,默认的python参数sock\u tls\u ver=ssl.PROTOCOL\u tls将为您完成工作,就像它应该尝试在所有tls版本上连接一样,因此,如果您的远程服务器仅支持TLSv1.2,即使您的python是使用TLSv1.3编译的,它也将使用TLSv1.2,并将按预期连接到TLS1.2,而不会出现任何问题

您可以检查您是否支持TLS版本打印布尔值

import ssl
print(ssl.HAS_TLSv1)
print(ssl.HAS_TLSv1_1)
print(ssl.HAS_TLSv1_2)
print(ssl.HAS_TLSv1_3)
希望这有助于消除SSL/TLS只是在发送任何套接字有价值的数据(如http请求)之前在客户端和服务器之间交换安全问题的一个小过程


顺便说一句,SSL将名称改为TLS,多年来一直被黑客攻击,这就是为什么我们有这么多版本,所以internet不像您认为的那样安全

您需要显示代码,甚至可能需要TLS握手的痕迹。通常情况下,任何性能良好的TLS客户端都以兼容的方式连接到TLS服务器,它们交换信息以选择双方可能接受的最高版本。这是每个主机的,因此您给出的示例不会影响其他主机的情况。保留这种行为是一个好主意,这样您就可以灵活地使用任何新版本。而TLS1.3比1.2更好。你的代码有不同的功能吗?没有。我使用reuqests库连接普通邮件。我得到了错误的握手:错误['SSL例程','tls\进程\服务器\证书','证书验证失败'],错误。有人告诉我这是因为我用的是TSL1.3。如何显示TSL握手的痕迹?证书验证失败与TLS版本无关。。。证书交换发生在版本协商之后,因此,如果您能够做到这一点,则意味着TLS版本在两端都被接受,不管它是什么。此错误消息意味着您在本地通常没有对收到的服务器证书进行签名的CA证书,因此无法对其进行验证。您可以使用openssl s_客户端在握手期间调试TLS问题。