六种实现层次对比
| 方案 | 典型工具 | 特点 |
|---|---|---|
| 用户态代理 | mitmproxy, Charles, Burp Suite | 配置简单,需安装根证书 |
| TUN 虚拟网卡 | Clash Meta, sing-box, Surge | 不依赖系统代理,可抓 UDP/游戏 |
| WinDivert | WinDivert + 自定义程序 | Windows 驱动层,游戏加速器常用 |
| WFP | 企业安全/DLP 产品 | 微软官方,性能高,不易检测 |
| NDIS Filter | Wireshark/Npcap | 二层帧,可抓所有流量 |
| Socket Hook | Frida, Xposed | 拦截加密前明文,绕过证书绑定 |
用户态代理(最常见)
流量路径:
App → 系统代理 → MITM Proxy → 目标服务器
HTTPS 需要:
- 生成 CA 根证书,安装到系统信任
- 收到
CONNECT hostname:443后,动态签发hostname的域名证书 - 与客户端建立一条 TLS,与服务端建立另一条 TLS,在中间解密/重新加密
TUN 虚拟网卡方案
App → 虚拟网卡(TUN) → 用户态协议栈 → 真实网卡
Linux 创建 TUN:
int tun_fd = open("/dev/net/tun", O_RDWR);
// 配置后:所有流量走 TUN,用户态读 IP 包
read(tun_fd, buf, sizeof(buf));
优点:不需要配系统代理,UDP 也能抓,Clash/sing-box 都用这套。
Python 实现最小 HTTPS MITM
第一步:生成 CA
openssl genrsa -out ca.key 2048
openssl req -x509 -new -key ca.key -out ca.crt -days 3650
安装 ca.crt 到系统根证书信任。
第二步:动态签发域名证书
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
import datetime
def gen_cert(hostname: str, ca_key, ca_cert):
key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
cert = (
x509.CertificateBuilder()
.subject_name(x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, hostname)]))
.issuer_name(ca_cert.subject)
.public_key(key.public_key())
.serial_number(x509.random_serial_number())
.not_valid_before(datetime.datetime.utcnow())
.not_valid_after(datetime.datetime.utcnow() + datetime.timedelta(days=365))
.add_extension(x509.SubjectAlternativeName([x509.DNSName(hostname)]), critical=False)
.sign(ca_key, hashes.SHA256())
)
return key, cert
第三步:TLS 劫持
import ssl
# 客户端侧:用伪造证书与客户端握手
def mitm_tls_client(client_socket, hostname, certfile, keyfile):
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ctx.load_cert_chain(certfile, keyfile)
return ctx.wrap_socket(client_socket, server_side=True)
# 服务端侧:正常连接真实服务器
def connect_server(hostname, port):
ctx = ssl.create_default_context()
raw = socket.create_connection((hostname, port))
return ctx.wrap_socket(raw, server_hostname=hostname)
两端建立后,中间就能读到明文 HTTP 请求:
req = client_tls.recv(8192)
print(req.decode()) # POST /v1/chat/completions ...
HTTP 解析推荐
不要手动解析 HTTP,使用成熟库:
pip install h11 # 轻量,推荐
# 或
pip install httptools
证书缓存
对同一域名动态生成一次后缓存,避免每次重复生成:
cert_cache = {}
def get_cert(hostname):
if hostname not in cert_cache:
key, cert = gen_cert(hostname, ca_key, ca_cert)
cert_cache[hostname] = (key, cert)
return cert_cache[hostname]
最小模块划分
自己实现一个基础 HTTPS MITM 代理,核心代码约 500~1000 行:
proxy/
├── listener.py # 监听连接
├── connect.py # 处理 CONNECT 方法
├── tls.py # TLS 劫持
├── cert.py # 动态证书生成/缓存
├── http.py # HTTP 解析
└── logger.py # 请求日志
局限性
用户态 HTTP Proxy 在以下场景会遇到问题:
- QUIC/HTTP3(基于 UDP,不走 CONNECT)
- App 硬编码不走系统代理
- Certificate Pinning(固定证书哈希)
- gRPC over HTTP2
对于需要捕获所有流量的场景(如 AI Agent 全局监听),TUN + gVisor Netstack 扩展性更好。
