python TLS套接字中的TLS会话恢复

时间:2018-08-01 07:20:21

标签: python-3.x sockets session ssl tls1.2

我在python中有一个简单的TLS客户端,可以连接到TLS服务器。我无法控制服务器。即使最近访问过,我也需要与每台服务器进行新的TLS握手。

1)默认情况下,非浏览器TLS客户端(例如以下python客户端)是否执行会话恢复?

2)我怎么知道他们是否这样做?如果在后台执行会话恢复,如何禁用它?

请注意,我为我连接到的每个新域创建了一个新套接字。

import socket, ssl

context = ssl.SSLContext() 
context.verify_mode = ssl.CERT_NONE 
context.check_hostname = False 

mycipher = "DHE-RSA-AES128-SHA"
context.set_ciphers(mycipher) 
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
domain = "google.com"
mySocket = context.wrap_socket(sock, server_hostname = domain) 
mySocket.connect((domain, 443))
mySocket.close()

3 个答案:

答案 0 :(得分:1)

这是一个困难但有趣的问题。而且您确实使用了适当的术语 TLS ,这给我带来了快乐;-)

首先,请注意,TLS1.3中的会话恢复已发生更改,因此这可能会对您将来产生影响(至少在命名(TLS1.3之前的版本中),此功能更多地介绍了会话和票证,而TLS1.3更喜欢谈论预共享密钥):https://timtaubert.de/blog/2017/02/the-future-of-session-resumption/

现在关于您的问题:

1)默认情况下,非浏览器TLS客户端(例如以下python客户端)是否会执行会话恢复?

  1. 位于https://docs.python.org/3.7/library/ssl.html的Python文档未提及“恢复”的任何内容;我想,如果它什么也没说,那就根本没有做。但这确实说明了“缓存”,这可能是同义词。
  2. 实际上,您可以在https://docs.python.org/3.7/library/ssl.html#ssl.SSLSession上注意到该会话具有以下属性:ticket_lifetime_hinthas_ticket;这应该与恢复有关。
  3. 现在看看https://docs.python.org/3.7/library/ssl.html#ssl.SSLContext.options,如果浏览所有可能的值,则会得到:

      

    ssl.OP_NO_TICKET     阻止客户端请求会话票证。

  4. 所以我在1)中的假设可能是错误的,并且默认情况下您已恢复会话。您应该使用上面的选项将其禁用

  5. (相反)似乎存在于PyOpenSSL中(相对于股票ssl),因为这里甚至还有一个问题,关于如何为该库禁用此功能:{{ 3}}

  6. 凭经验,您可以尝试通过以下方式运行该应用程序,使其在近时间内两次连接到同一端点,并查看交换了哪种TLS消息,从而发现这一点。例如,在TLS 1.3中(应该与其他版本相似,但某些名称可能会更改),新的握手从ClientHello / ServerHello开始,其中恢复从相同的消息开始但以{{1 }} 延期。它的存在将显示TLS恢复。在TLS 1.2中,客户端将在恢复握手期间发送pre_shared_key扩展名。

2)我怎么知道他们是否这样做?如果在后台执行会话恢复,该如何禁用呢?

  1. 如果我对上述说法是正确的,请确保在SSL上下文对象中使用SessionTicket。否则默认情况下,它是ssl.OP_NO_TICKET,其中包含旨在最大化互操作性的各种选项,但内容可能会有所不同,具体取决于您的Python版本和所使用的基础OpenSSL库。
  2. 如果您的会话具有OP_ALL属性,我猜它使用TLS恢复或已设置为使用它。

答案 1 :(得分:0)

  

1)默认情况下,非浏览器TLS客户端(例如以下python客户端)是否会执行会话恢复?

默认情况下,python tls / ssl库不执行会话恢复。

  

2)我怎么知道他们是否这样做?如果在后台执行会话恢复,如何禁用它?

您可以使用以下代码来验证是否未恢复会话:

import socket
import ssl

hostname = 'www.stackoverflow.com'
context = ssl.create_default_context()

# Create a new socket, then create a secure socket
sock = socket.create_connection((hostname, 443))
ssock = context.wrap_socket(sock, server_hostname=hostname)

# Was the TLS Session re-used?
print(ssock.session_reused) # False

答案 2 :(得分:0)

TLS 会话恢复可以通过使用最后一个 ssl 会话来启用。

hostname = 'google.com'
port = 443
resource = '/'

context = ssl.SSLContext(ssl.PROTOCOL_TLS)

sock = socket.create_connection((hostname, port))
ssock = context.wrap_socket(sock, server_hostname=hostname)

#send - receive

ssr = ssock.session
print(ssock.session_reused) # False
ssock.close()



sock = socket.create_connection((hostname, port))
ssock = context.wrap_socket(sock, server_hostname=hostname, session=ssr)

#send - receive

print(ssock.session_reused) # True , if server support it

ssock.close()