【问题标题】:TLS session resumption in python TLS socketpython TLS套接字中的TLS会话恢复
【发布时间】:2019-01-08 16:24:54
【问题描述】:

我在 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()

【问题讨论】:

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


    【解决方案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),因为这里甚至还有一个关于如何为该库禁用此功能的问题:How to disable session resumption in pyOpenSSL?

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

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

    1. 如果我对上述内容正确,请确保在 SSL 上下文对象中使用 ssl.OP_NO_TICKET。否则默认为OP_ALL,它包含各种旨在最大化互操作性的选项,但内容可能会根据您的 Python 版本和使用的底层 OpenSSL 库而变化。
    2. 如果您的会话填充了 has_ticket 属性,我猜它使用 TLS 恢复或设置为使用它。

    【讨论】:

    • 谢谢。还有一件事。如果客户端使用set_ciphers 更改其密码套件。即,客户端使用密码套件与服务器进行第一次握手,然后客户端使用set_ciphers 更改其密码套件,然后,客户端与同一服务器进行第二次握手(就在第一次之后)。会话恢复仍然可以使用吗?客户端更改密码是否会强制执行新的握手?确定对我来说有点棘手,因此我将感谢您的帮助。
    • 我说的是 TLS 1.2。
    • 你能检查我的问题here
    • 您从哪里得到可以即时更改密码的印象?确实,该消息称为 ChangeCipherSpec 但这只是在握手开始时交换,而不是在飞行中。参见 TLS1.2:ChangeCipherSpec 消息在握手期间在安全参数达成一致后发送,但在发送验证 Finished 消息之前。.
    • 非常感谢您的帮助。你能检查我的后续问题here吗?
    【解决方案2】:

    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
    

    【讨论】:

      【解决方案3】:

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

      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()
      

      【讨论】:

        猜你喜欢
        • 2020-05-21
        • 2016-09-10
        • 1970-01-01
        • 2019-11-20
        • 2013-08-26
        • 1970-01-01
        • 2011-12-08
        • 1970-01-01
        • 2017-10-22
        相关资源
        最近更新 更多