在 Python 的 WSGI/ASGI 框架中如何讀取客戶端請求的 TLS 指紋?

python WSGI/ASGI 框架中如何讀取客戶端請求的 TLS 指紋

python 生態(tài)系統(tǒng)中,尤其是使用 wsgi/asgi 框架時,讀取客戶端請求的 tls 指紋是一個常見但相對復(fù)雜的問題。許多開發(fā)者嘗試使用 request.scope.get(‘ssl’) 來獲取 tls 相關(guān)信息,但經(jīng)常發(fā)現(xiàn)這個方法并不可靠。下面我們將詳細(xì)探討如何在 python 的 uvicorn 和 fastapi 環(huán)境中以及使用純 socket 編程的方式獲取客戶端的 tls 指紋。

使用 Uvicorn 和 FastAPI

首先,讓我們來看一下在 uvicorn 和 fastapi 環(huán)境中如何嘗試獲取 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 版本和環(huán)境可能有所不同</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 信息,但發(fā)現(xiàn)該方法在許多情況下返回的是 None。這可能是因為 FastAPI 并不直接暴露 TLS 信息。

使用純 socket 編程

考慮到在 FastAPI 中獲取 TLS 指紋的困難,我們嘗試使用純 socket 編程來直接處理客戶端的 TLS 握手過程。以下是示例代碼:

立即學(xué)習(xí)Python免費學(xué)習(xí)筆記(深入)”;

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 模塊來設(shè)置 TLS 服務(wù)器,并且使用 pyja3 庫嘗試提取 JA3 指紋。然而,實際操作中,我們可能仍然無法讀取到客戶端請求中的 TLS 指紋。

解決方案和討論

在當(dāng)前的 Python WSGI/ASGI 生態(tài)系統(tǒng)中,讀取 TLS 指紋并不直接支持。無論是使用 FastAPI 還是純 socket 編程,都遇到了困難。這主要是因為 TLS 信息通常在底層網(wǎng)絡(luò)層處理,應(yīng)用層無法直接訪問這些信息。

要解決這個問題,可以考慮以下方法:

  1. 使用中間件:某些 Web 服務(wù)器(如 Nginx)可以作為反向代理,并通過中間件或插件來捕獲和記錄 TLS 信息。然后,這些信息可以通過 HTTP 頭或其他方式傳輸給應(yīng)用服務(wù)器。
  2. 使用專用庫:某些專門用于 TLS 指紋分析的庫可能會提供更直接的方法來提取所需信息。
  3. 調(diào)整服務(wù)器配置:在某些情況下,調(diào)整服務(wù)器的配置文件(例如 Nginx 配置)以記錄 TLS 信息可能是一個可行的解決方案。

總之,讀取客戶端請求的 TLS 指紋在 Python 的 WSGI/ASGI 框架中需要更深入的網(wǎng)絡(luò)層處理或借助外部工具和配置來實現(xiàn)。

在 Python 的 WSGI/ASGI 框架中如何讀取客戶端請求的 TLS 指紋?

? 版權(quán)聲明
THE END
喜歡就支持一下吧
點贊9 分享