如何在Python Twisted Web服务器中获取TLS握手原始数据包计算JA3?
在Twisted Web服务器中获取TLS Client Hello原始字节的方案
要在Twisted Web服务器中捕获TLS握手的原始字节(如Client Hello用于JA3计算),核心是替换默认的TLS协议处理类,在TLS层拦截握手数据包。以下是可行的实现步骤:
1. 自定义TLS协议类
重写TLSMemoryBIOProtocol的dataReceived方法,检测并存储Client Hello数据:
from twisted.protocols import tls class CustomTLSMemoryBIOProtocol(tls.TLSMemoryBIOProtocol): def dataReceived(self, bytes_data): # 匹配TLS记录层(类型0x16=握手协议)及Client Hello握手类型(0x01) if len(bytes_data) > 5 and bytes_data[0] == 0x16: # 检查是否为TLS 1.0/1.1/1.2版本 if bytes_data[1] == 0x03 and bytes_data[2] in (0x01, 0x02, 0x03): handshake_type = bytes_data[5] if handshake_type == 0x01: # 将Client Hello绑定到被包裹的HTTP通道实例上 self.wrappedProtocol.client_hello = bytes_data # 调用父类方法继续完成TLS握手流程 super().dataReceived(bytes_data)
2. 修改服务器配置,使用自定义TLS协议
在listenSSL调用中指定自定义协议类,替换默认的TLSMemoryBIOProtocol:
from twisted.web import server, resource from twisted.internet import reactor, ssl class IndexResource(resource.Resource): isLeaf = True def render_GET(self, request): # 从HTTP通道中获取已存储的Client Hello数据 client_hello = getattr(request.channel, 'client_hello', b'') if client_hello: # 此处可添加JA3计算等后续处理逻辑 print(f"捕获到Client Hello(前100字节): {client_hello[:100]}...") return b"Hello, TLS World!" def get_https_endpoint(): ssl_context = ssl.DefaultOpenSSLContextFactory( "services/web/certs/key.pem", "services/web/certs/cert.pem" ) https_factory = server.Site(IndexResource()) # 关键:传入自定义TLS协议类 return reactor.listenSSL( config["service"]["port"]["https"], https_factory, ssl_context, protocol=CustomTLSMemoryBIOProtocol ) if __name__ == "__main__": get_https_endpoint() reactor.run()
关键说明
- 避免自定义构造函数:Twisted会自动调用
TLSMemoryBIOProtocol的构造函数,额外添加参数会导致调用失败,因此直接继承父类构造函数即可。 - 数据传递:将Client Hello存储到
wrappedProtocol(即Twisted的HTTPChannel实例)上,后续可通过request.channel在Web资源中访问。 - 分片处理(可选):如果需要处理分片的Client Hello,可根据TLS记录层的长度字段(
bytes_data[3:5]为大端格式的长度值)拼接数据,确保获取完整的握手包。
内容的提问来源于stack exchange,提问作者Aleksander Rodionov
相关产品推荐
相关产品推荐

