在 Python 的 WSGI/ASGI 框架中如何读取客户端请求的 TLS 指纹?

python WSGI/ASGI 框架中如何读取客户端请求的 TLS 指纹

python 生态系统中,尤其是使用 wsgi/asgi 框架时,读取客户端请求的 tls 指纹是一个常见但相对复杂的问题。许多开发者尝试使用 request.scope.get(‘ssl’) 来获取 tls 相关信息,但经常发现这个方法并不可靠。下面我们将详细探讨如何在 python 的 uvicorn 和 fastapi 环境中以及使用纯 socket 编程的方式获取客户端的 tls 指纹。

使用 Uvicorn 和 FastAPI

首先,让我们来看一下在 uvicorn 和 fastapi 环境中如何尝试获取 TLS 指纹。以下是示例代码:

import uvicorn from loggers import logger from fastapi import FastAPI, Request from fastapi.middleware.cors import CORSMiddleware from middleware.loggers import RequestLogMiddleware from middleware.correlations import CorrelationIdMiddleware from starlette.middleware.base import BasehttpMiddleware <p>app = FastAPI()</p><p>app.add_middleware( CORSMiddleware, allow_origins=['<em>'], allow_credentials=True, allow_methods=["</em>"], allow_headers=["*"], ) app.add_middleware(BaseHTTPMiddleware, dispatch=RequestLogMiddleware()) app.add_middleware(BaseHTTPMiddleware, dispatch=CorrelationIdMiddleware())</p><p>@app.get('/') @logger.catch async def root(request: Request): ssl_info = request.scope.get('ssl') if ssl_info:</p><h1>尝试获取 TLS 指纹,不同的 Python 版本和环境可能有所不同</h1><pre class="brush:php;toolbar:false">    tls_fingerprint = ssl_info.get('peer_cert_fingerprint')     if tls_fingerprint:         logger.info(f"Client TLS fingerprint: {tls_fingerprint}")     else:         logger.info("Could not get client TLS fingerprint.") else:     logger.info("No SSL information available.")  response_body = {     "ip": request.client.host } logger.debug(response_body)  return response_body

if name == “main“: uvicorn.run( app, host=”0.0.0.0”, port=8086, workers=1, ssl_keyfile=”/Users/ponponon/Downloads/xxxx.cn_nginx/xxxx.cn.key”, ssl_certfile=”/Users/ponponon/Downloads/xxxx.cn_nginx/xxxx.cn.pem” )

如上所述,尝试通过 request.scope.get(‘ssl’) 访问 TLS 信息,但发现该方法在许多情况下返回的是 None。这可能是因为 FastAPI 并不直接暴露 TLS 信息。

使用纯 socket 编程

考虑到在 FastAPI 中获取 TLS 指纹的困难,我们尝试使用纯 socket 编程来直接处理客户端的 TLS 握手过程。以下是示例代码:

立即学习Python免费学习笔记(深入)”;

import ssl import socket from loguru import logger from pyja3 import extract_ja3_from_client_hello from threading import Thread</p><p>CERT_FILE = "/home/pon/code/me/ssl/xxxx.cn_nginx/xxxx.cn.pem" KEY_FILE = "/home/pon/code/me/ssl/xxxx.cn_nginx/xxxx.cn.key"</p><p>def handle_client(client_socket, addr): try: raw_data = client_socket.recv(4096, socket.MSG_PEEK) ja3_str, ja3_hash = extract_ja3_from_client_hello(raw_data) logger.info(f"[{addr}] JA3: {ja3_str}, MD5: {ja3_hash}") except Exception as e: logger.warning(f"[{addr}] Failed to get JA3: {e}") finally: client_socket.close()</p><p>def main(): context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) context.load_cert_chain(certfile=CERT_FILE, keyfile=KEY_FILE)</p><pre class="brush:php;toolbar:false">bindsocket = socket.socket() bindsocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) bindsocket.bind(("0.0.0.0", 8086)) bindsocket.listen(5)  logger.info("Server listening on 0.0.0.0:8086")  while True:     client_socket, fromaddr = bindsocket.accept()     Thread(target=handle_client, args=(client_socket, fromaddr)).start()

if name == “main“: main()

在上述代码中,我们使用 ssl 和 socket 模块来设置 TLS 服务器,并且使用 pyja3 库尝试提取 JA3 指纹。然而,实际操作中,我们可能仍然无法读取到客户端请求中的 TLS 指纹。

解决方案和讨论

在当前的 Python WSGI/ASGI 生态系统中,读取 TLS 指纹并不直接支持。无论是使用 FastAPI 还是纯 socket 编程,都遇到了困难。这主要是因为 TLS 信息通常在底层网络层处理,应用层无法直接访问这些信息。

要解决这个问题,可以考虑以下方法:

  1. 使用中间件:某些 Web 服务器(如 Nginx)可以作为反向代理,并通过中间件或插件来捕获和记录 TLS 信息。然后,这些信息可以通过 HTTP 头或其他方式传输给应用服务器。
  2. 使用专用库:某些专门用于 TLS 指纹分析的库可能会提供更直接的方法来提取所需信息。
  3. 调整服务器配置:在某些情况下,调整服务器的配置文件(例如 Nginx 配置)以记录 TLS 信息可能是一个可行的解决方案。

总之,读取客户端请求的 TLS 指纹在 Python 的 WSGI/ASGI 框架中需要更深入的网络层处理或借助外部工具和配置来实现。

在 Python 的 WSGI/ASGI 框架中如何读取客户端请求的 TLS 指纹?

© 版权声明
THE END
喜欢就支持一下吧
点赞9 分享