بنقرة واحدة
dpi-audit
修改 TLS 握手、ALPN 协商、ClientHello/ServerHello 处理、伪装方案代码后触发。
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
修改 TLS 握手、ALPN 协商、ClientHello/ServerHello 处理、伪装方案代码后触发。
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
写入新模块文档、重构模块、或用户要求分析模块时触发。
Bug 修复或对接问题排查确认有效后,将经验记录到知识库。
修改 PMR 分配器、内存池配置、热路径容器、对象生命周期管理代码后触发。
编写或修改性能基准测试、分析 benchmark 结果、优化热路径性能时触发。
新增或修改 enable_shared_from_this 类、co_spawn 调用、shared_ptr 捕获的 lambda、co_await 后的成员访问时触发。
新增或修改原子操作、异步定时器、无锁通道、跨线程状态同步、CAS 竞争相关代码时触发。
| name | dpi-audit |
| description | 修改 TLS 握手、ALPN 协商、ClientHello/ServerHello 处理、伪装方案代码后触发。 |
在修改涉及 TLS 握手、协议识别、伪装方案代码后,必须对变更部分执行以下审计清单。
审查系统在 TLS 握手阶段运行指纹黑名单机制:提取 ClientHello 的密码套件列表、扩展字段及顺序、椭圆曲线等信息计算指纹(如 JA3/JA4),与已知的非浏览器指纹库比对。Go 标准库、Python requests、已知代理工具的指纹已被收录,命中即阻断。
同时审查系统会进行多维度交叉验证:SNI 与证书 CN/SAN 是否一致、证书是否由受信 CA 签发、ALPN 协商结果与后续流量是否匹配。任何一项不一致都可能触发阻断。
指纹检测不止于 TLS。TCP/IP 栈指纹(初始 TTL、TCP 窗口大小、TCP 选项顺序)可以识别操作系统。如果 TLS 指纹声称是 Chrome/Windows,但 TCP/IP 栈指纹显示是 Linux 内核,这种交叉矛盾会直接暴露伪装。
审查系统的指纹检测是持续进化的:Chrome 每次大版本更新可能改变扩展顺序或新增扩展。如果代理软件的指纹停留在旧版 Chrome 特征,审查系统可以通过版本差异识别出"永不更新的 Chrome",这本身就是异常。
此外,审查系统不只检查 ClientHello 指纹。TLS 库的服务端行为指纹同样可识别:BoringSSL、OpenSSL、LibreSSL 在密码套件选择偏好、扩展处理细节、错误响应格式上都有差异。如果 ClientHello 声称是 Chrome(使用 BoringSSL),但服务端行为显示 OpenSSL 特征,这种不匹配暴露伪装。
适用范围:ClientHello 指纹审计适用于出站连接(Prism 作为客户端连接 dest 服务器时的 ClientHello 构造)。入站连接的 ClientHello 由下游客户端发送,Prism 仅解析不做控制。ServerHello 指纹仅适用于 Reality 方案(手动构造 ServerHello),ShadowTLS/Restls 继承后端服务器的 ServerHello 指纹。
TLS ClientHello 是 DPI 审查的首要目标。审查系统提取以下字段计算指纹哈希,与已知浏览器指纹库进行比对。任何一个字段的不一致都可能导致指纹失配。
| 检查项 | 说明 |
|---|---|
| 密码套件顺序 | 加密套件列表及其排列顺序是否与目标浏览器完全一致?审查系统维护黑名单,已知非浏览器指纹直接阻断。顺序差异即使只有一个套件位置不同,也会产生不同的 JA3/JA4 哈希 |
| 扩展字段完整性 | supported_groups、key_share、signature_algorithms、psk_key_exchange_modes、session_ticket 等扩展是否与目标浏览器模板匹配?缺失扩展本身就是异常特征。Chrome 通常携带 15+ 个扩展 |
| 扩展顺序一致性 | 扩展字段的排列顺序是否与目标浏览器完全一致?不同客户端的扩展顺序是可区分的。例如 Chrome 的典型顺序:0x000b (ec_point_formats) → 0x000a (supported_groups) → 0x000d (signature_algorithms) → 0x0016 (ALPN) → ... |
| 扩展内部值顺序 | 不仅扩展的顺序要一致,每个扩展内部的值也要一致。如 signature_algorithms 列表中算法的排列顺序(如 rsa_pss_rsae_sha256 在 rsa_pkcs1_sha256 前还是后)、supported_groups 中曲线的排列顺序(如 x25519 在 secp256r1 前还是后) |
| GREASE 值 | Chrome 等浏览器在密码套件列表、扩展列表、ALPN 列表、supported_groups、key_share 中填充 GREASE 随机值,用于前瞻兼容性测试。已知 GREASE 值包括 0x0a0a、0x1a1a、0x2a2a、0x3a3a、0x4a4a、0x5a5a、0x6a6a、0x7a7a、0x8a8a、0x9a9a、0xaaaa、0xbaba、0xcaca、0xdada、0xeaea、0xfafa。缺少 GREASE 值是非浏览器客户端的强特征 |
| 后量子密钥交换 | Chrome 已在 key_share 扩展中包含 ML-KEM-768(Kyber-768)密钥共享。ML-KEM-768 的 key_share 数据长度固定为 1184 字节,加上 X25519 的 32 字节,使 ClientHello 总长度膨胀到约 1700 字节。如果代理的 ClientHello 缺少 ML-KEM 密钥共享或 key_share 数据长度不等于 1184 字节,审查系统可以通过缺失的后量子扩展识别出"非最新 Chrome"。Chrome 同时发送 X25519 + ML-KEM-768 两个 key_share |
| Chrome 124+ 扩展随机化 | Chrome 124 引入了会话级随机化:每次 TLS 连接的 GREASE 位置和非关键扩展的顺序都会随机变化。静态模板(硬编码扩展顺序)不再匹配最新 Chrome 的行为。代理必须实现同样的随机化逻辑,否则"每次连接扩展顺序完全相同"本身就是非浏览器特征 |
| TLS 版本列表 | supported_versions 扩展是否包含且仅包含目标版本?现代 Chrome 仅包含 0x0304 (TLS 1.3),加上 GREASE 值。多余的旧版本(如包含 0x0303)或缺少版本会暴露非浏览器特征 |
| ClientHello.random | 必须为密码学安全伪随机数(CSPRNG),不得使用可预测的随机源、固定种子或存在模式。32 字节全零或具有可识别模式的随机数是严重漏洞 |
| 指纹版本追踪 | 指纹模板是否跟随目标浏览器版本更新?停滞在旧版 Chrome 特征的"永不更新的客户端"本身就是异常。需要建立指纹模板的持续更新机制,至少跟踪每个 Chrome 大版本号的指纹变化 |
| JA4+ 指纹体系 | JA4 是 JA3 的进化版,分组更细。JA4(客户端指纹)按 SNI 是否存在、ALPN 是否存在将扩展分组编码。JA4S(服务端指纹)编码 ServerHello 的密码套件选择和扩展响应。JA4X(证书指纹)编码证书的密钥类型、签名算法、有效期范围。代理的 ClientHello 必须在所有 JA4 维度上与目标浏览器匹配 |
| ClientHello 总长度合规 | ClientHello 总长度是否与目标浏览器版本一致?含后量子密钥交换(ML-KEM-768)的 Chrome ClientHello 约 1700 字节,不含约 500 字节。异常短或异常长的 ClientHello 都是可识别特征。审查系统可通过 ClientHello 长度直接判断是否使用了后量子密钥交换 |
GREASE 值必须出现在以下位置,且每个位置最多出现一次:
每个位置使用的具体 GREASE 值应从 16 个已知值中随机选择,且各位置独立随机。
⚠️ 实现验证:当前 Prism 的 tls.cpp 中 GREASE 仅存在于注释,实际未通过 SSL_CTX_set_grease 等 API 启用。审计时应验证 GREASE 在 BoringSSL context 中是否真正生效,而非仅检查注释。客户端方向的 GREASE 已通过 BoringSSL 自动处理。
key_share 扩展内部结构:
- X25519 key_share: group=0x001d, data_length=32, data=<32 bytes CSPRNG>
- ML-KEM-768 hybrid key_share: group=0x11EC (IANA 最终分配), data_length=1218
(X25519 32B + ML-KEM-768 1184B + 2B 头), data=<CSPRNG>
验证要点:
指纹模板必须持续跟随目标浏览器版本更新。停滞在旧版特征的"永不更新的客户端"本身就是异常。
指纹版本号:每个指纹模板标注目标 Chrome 大版本号(如 Chrome 126)。模板更新时同步更新版本号,记录变更日期。
更新触发(Chrome 约 4 周一个大版本):
验证方法:
回归测试:每次指纹模板更新后,运行 RealityBench 及相关 benchmark 确认握手成功率无回归。
存放位置:在 docs/wiki/fingerprints/ 目录下维护各版本的指纹快照(JSON 格式),包含字段:
{
"chrome_version": "126",
"capture_date": "2026-05-29",
"cipher_suites": [...],
"extensions": [{"id": "0x...", "name": "...", "order": 1}],
"supported_groups": [...],
"signature_algorithms": [...],
"key_share_groups": ["x25519", "ml-kem-768"],
"alpn": [...],
"total_hello_length": 1700
}
ServerHello 是服务端指纹的核心来源。审查系统通过 ServerHello 的字段选择反推服务端 TLS 库类型。
| 检查项 | 说明 |
|---|---|
| 版本号固定 | legacy_version 必须为 0x0303(TLS 1.2 兼容格式),supported_versions 扩展中必须为 0x0304(TLS 1.3)。不得使用 0x0301 作为 legacy_version,也不得在 supported_versions 中返回非 TLS 1.3 的值 |
| random 字段 | 必须为密码学安全随机数,不得包含可识别的模式或固定字节。在 HelloRetryRequest 场景中,random 必须为特殊的 hello_retry_request 常量值(RFC 8446 §4.1.3 定义) |
| cipher_suite 选择 | 必须从 ClientHello 提供的列表中选择,且选择逻辑与主流服务器行为一致。选择逻辑本身是 TLS 库指纹(见第 3 节) |
| 证书质量 | 证书是否由受信 CA 签发?CN/SAN 是否与 SNI 匹配?证书链是否完整?证书的有效期、密钥类型、签名算法是否与主流 Web 服务器证书一致? |
| 扩展响应完整性 | ServerHello 必须包含 key_share、supported_versions 扩展。如果使用了 PSK,还必须包含 pre_shared_key 扩展。缺少预期扩展或返回非预期扩展都是指纹 |
| session_id 回显 | 必须原样回显 ClientHello 中的 session_id,不得修改或截断。TLS 1.3 中 session_id 仅用于兼容性,但值必须匹配 |
这是最容易被忽视但最致命的指纹维度。审查系统不仅看 ClientHello,也分析服务端行为来反推 TLS 库类型。如果 ClientHello 模拟了 Chrome/BoringSSL 特征,但服务端行为暴露了 OpenSSL 特征,这种不一致直接暴露伪装。
| 行为维度 | BoringSSL(Chrome/Google 服务端) | OpenSSL |
|---|---|---|
| 密码套件选择偏好 | AES-GCM 优先,然后是 ChaCha20-Poly1305。始终优先选择有硬件加速的算法 | 无 AES-NI 时 ChaCha20 优先(OpenSSL 1.1.1+ 的策略)。有 AES-NI 时 AES-GCM 优先 |
| HelloRetryRequest 格式 | HRR 中的扩展顺序与 BoringSSL 实现一致。key_share 扩展在 selected_version 之后的特定位置 | HRR 中扩展顺序不同,可能在 cookie 处理上有差异 |
| MAC 失败 Alert | 返回 bad_record_mac(描述码 20)。这是 RFC 规定的标准行为 | 可能返回 decrypt_error(描述码 51)。偏离 RFC 但不影响互操作性 |
| 记录层版本号 | 始终使用 0x0303,包括握手阶段 | 握手阶段可能使用 0x0301(SSL 3.0 兼容)。这种差异可被被动检测 |
| OCSP Stapling | Google 服务端通常启用 OCSP Stapling,在 TLS 握手中返回 Certificate Status 消息 | 未配置时完全不返回 OCSP 响应。缺失 OCSP Stapling 在高信誉域名上可疑 |
| Certificate Compression | 支持 compress_certificate 扩展(brotli/zstd),响应中可能使用压缩证书 | 默认不支持 Certificate Compression。不支持此扩展与声称的服务器类型不一致时可疑 |
| NewSessionTicket 行为 | 握手完成后发送的 NST 消息格式、ticket 生命周期、max_early_data_size 与 BoringSSL 实现一致 | NST 格式和参数可能不同。ticket 结构是 TLS 库指纹 |
| Alert 消息格式 | TLS 1.3 中 Alert 使用 ApplicationData 记录加密传输(除握手阶段的致命 Alert) | 行为一致,但 Alert 描述码的选择可能不同 |
证书是审查系统进行域名关联和伪装检测的核心锚点。
| 检查项 | 说明 |
|---|---|
| 证书签发方式 | 审查系统直接阻断自签名证书。证书必须由受信 CA 签发或伪造得足以通过链验证。使用 Let's Encrypt 等免费 CA 是可行方案,但需注意批量申请的行为异常 |
| CN/SAN 与 SNI 一致 | 证书的 CN(Common Name)和 SAN(Subject Alternative Name)必须与 ClientHello 中的 SNI 匹配。不匹配会被审查系统直接封锁 |
| 证书链完整性 | 证书链是否包含完整的中级证书?缺少中间 CA 证书会导致验证失败。证书链中不应包含多余的非必要证书 |
| 批量申请异常 | 大量域名集中申请免费 CA 证书的行为会触发降级审查。申请模式应分散化,避免时间或 IP 集中的批量特征 |
| 证书透明度日志 | 所有公开受信 CA 签发的证书都会被记入 CT Log,可被事后关联分析。伪造证书的注册模式(域名选择、申请时间、申请频率)应避免批量特征 |
| 证书字段一致性 | 证书的密钥类型(RSA/ECDSA)、签名算法、有效期范围应与主流 Web 服务器证书一致。异常的密钥长度或过期时间本身是指纹 |
| 回落目标可达性 | 回落目标是否指向真实可达的高信誉第三方域名?不可达的目标会导致回落失败,间接暴露代理行为 |
ALPN 协商是 TLS 握手中可被审查的关键字段,且协商结果必须与后续实际流量行为完全一致。
| 检查项 | 说明 |
|---|---|
| ALPN 设置方式 | 必须使用回调函数在每次握手时动态选择 ALPN,而非在共享 SSL_CTX 上设置固定 ALPN 列表。后者会污染所有连接,导致所有连接协商出相同的 ALPN 结果——这在多域名场景下是异常行为 |
| ALPN 与实际流量一致 | 如果协商结果为 h2,后续流量必须真正体现 HTTP/2 帧结构(以 SETTINGS 帧开头,使用 HPACK 头部压缩,遵守流控制等)。如果协商了 h2 但实际传输的是非 HTTP/2 数据,状态机关联分析会检测到这种不一致 |
| ALPN 降级处理 | 客户端不支持所需 ALPN 时,是否正确降级到安全传输模式?降级时应将连接作为标准 TLS 传输转发到回落目标,而非暴露代理行为 |
| ALPN 选择逻辑 | ALPN 选择逻辑是否与目标服务器的行为一致?真实 Web 服务器通常优先选择 h2,然后是 http/1.1。选择逻辑的顺序偏好本身是服务端指纹 |
| 无 ALPN 扩展处理 | 如果 ClientHello 不包含 ALPN 扩展,服务端不得在 ServerHello 中返回 ALPN 扩展。这是 RFC 规范要求 |
TLS 握手是一个严格的状态机,每个状态的转换都必须与标准实现完全一致。
| 检查项 | 说明 |
|---|---|
| 状态转换序列 | TLS 1.3 握手的状态转换序列是否与目标实现完全一致?不只是"字段匹配",而是整个状态机转换序列都必须模拟。包括:ClientHello → ServerHello/HelloRetryRequest → EncryptedExtensions → Certificate → CertificateVerify → Finished → Finished |
| CCS 插入时机 | ChangeCipherSpec(CCS)兼容性记录的插入时机必须正确。TLS 1.3 中 CCS 仅用于中间件兼容性,必须在 ServerHello 之后、Finished 之前的正确位置插入。过早或过晚的 CCS 都是状态机异常 |
| Finished 消息顺序 | 服务端的 Finished 消息必须在 Certificate + CertificateVerify 之后发送。客户端的 Finished 消息必须在收到服务端 Finished 之后发送。顺序错误违反 TLS 1.3 协议规范 |
| 错误状态转换 | 收到非预期消息时的状态转换是否与标准实现一致?例如在等待 ServerHello 时收到 ApplicationData 的处理。自定义的错误处理路径(如不发送 Alert 直接断开)本身就是指纹 |
| 重协商行为 | TLS 1.3 不支持重协商。收到重协商请求(TLS 1.2 的 HelloRequest)时,必须按照标准行为拒绝(发送 no_renegotiation Alert),而非忽略或断开 |
| 协议降级防御 | 审查系统可能强制协议降级(如发送仅支持 TLS 1.2 的 ClientHello)。如果服务端在降级后的行为与标准 TLS 1.2 实现不一致,降级路径暴露指纹。必须确保 TLS 1.2 降级路径同样合规 |
| 0-RTT 处理 | 如果支持 0-RTT,必须正确处理 early data 的接收和拒绝逻辑。不当的 0-RTT 处理可能导致重放攻击或状态机异常 |
握手完成后的第一个应用层数据包是审查系统的第二个检测窗口。
| 检查项 | 说明 |
|---|---|
| HTTP/2 SETTINGS 帧首发 | 握手完成后第一个应用层帧必须为 HTTP/2 SETTINGS 帧。非标准帧序列(如直接发送 HEADERS 或 DATA 帧)是异常。SETTINGS 帧的流 ID 必须为 0 |
| SETTINGS 参数值 | HTTP/2 SETTINGS 帧中的参数值是否与主流实现一致?关键参数包括:HEADER_TABLE_SIZE(HPACK 动态表大小)、INITIAL_WINDOW_SIZE(初始流控窗口)、MAX_FRAME_SIZE(最大帧大小)、MAX_CONCURRENT_STREAMS(最大并发流数)。自定义参数值是服务端指纹 |
| WINDOW_UPDATE 行为 | WINDOW_UPDATE 帧的频率和增量值是否与主流实现一致?异常的流量控制行为(如超大增量值、从不发送 WINDOW_UPDATE)是服务端指纹 |
| 流优先级 | 是否正确处理 HTTP/2 的流优先级和依赖关系?完全忽略 PRIORITY 帧或使用非标准权重值是简化实现的标志 |
| Session Resumption 行为 | 正常浏览器利用 TLS session resumption 或 0-RTT 减少握手延迟。如果代理的每次连接都是完整握手(缺少 session resumption),本身是异常特征。应支持 Session Ticket 复用,且 NewSessionTicket 的 ticket lifetime、max_early_data_size 等参数与目标服务器一致 |
| HTTP/2 GOAWAY 处理 | 连接关闭时是否正确发送 GOAWAY 帧?直接断开不发送 GOAWAY 是非标准行为 |
| HTTP/2 PING 行为 | 是否正确响应 PING 帧?不响应 PING 或响应内容不正确(必须原样回传 opaque data)是异常 |
| HTTP/1.1 行为 | 如果协商了 http/1.1,后续数据是否遵循 HTTP/1.1 格式(请求行、头部、CRLF 分隔)?混用协议格式会被检测 |
| EncryptedExtensions 指纹 | Reality 发送空 EncryptedExtensions(0 字节扩展),而标准 BoringSSL 服务端会发送 ALPN、extended_master_secret 等扩展。此差异可被指纹识别。审计时应评估是否需要补充标准扩展 |
| NewSessionTicket 缺失 | Reality 握手后不发送 NewSessionTicket,而标准 TLS 1.3 服务端至少发送一个 NST。缺少 NST 是异常行为,可被用于区分 Reality 与标准 TLS 服务端 |
SNI(Server Name Indication)是审查系统关联客户端意图的核心字段,处理不当会导致安全风险。
| 检查项 | 说明 |
|---|---|
| SNI 白名单 | 服务端 SNI 白名单是否只包含经过审查的高流量、高信誉域名?白名单应避免包含敏感域名(如被封锁域名)或低信誉域名 |
| 空 SNI 防御 | 空 SNI 的连接必须安全回落到下一个伪装方案或转发到真实目标,不得直接拒绝连接或返回异常响应。直接拒绝空 SNI 会暴露代理行为特征:真实 Web 服务器不会因为空 SNI 而断开连接 |
| SNI 交叉验证 | 服务端返回的证书 CN/SAN 必须与 ClientHello 中的 SNI 匹配。不匹配的证书会被审查系统标记 |
| SNI 长度校验 | SNI 的域名长度不得超过 DNS 规范限制(253 字节)。每段标签不得超过 63 字节。超长 SNI 可能是缓冲区溢出攻击或指纹探测 |
| 通配符 SNI 处理 | 通配符域名(如 *.example.com)的处理逻辑是否正确?通配符仅匹配一级子域名 |
| SNI 编码安全 | SNI 必须为有效的 DNS 名称(小写 ASCII,无尾随点)。包含非 ASCII 字符、下划线或其他非法字符的 SNI 应安全回落 |
ECH(Encrypted Client Hello)和 ESNI(Encrypted SNI)是 SNI 加密方案,但审查系统对此有明确的对抗策略。
| 检查项 | 说明 |
|---|---|
| ECH 扩展检测 | 审查系统对携带 ECH(extension type 0xFE0D)或老版 ESNI 扩展的 ClientHello 采取高概率丢弃或注入 RST。原因:审查系统无法窥探加密后的 SNI,宁可误杀不可放过 |
| ECH 禁用决策 | 短期内为确保连通率可能需要禁用 ECH,但这牺牲了 SNI 隐私。需根据部署环境的审查强度权衡连通率与隐私 |
| ECH 外部 SNI | 即使启用 ECH,ClientHello 仍包含明文的外部 SNI(outer SNI),指向 ECH 配置服务商。审查系统可能将已知 ECH 服务商域名列入高审查名单 |
| 替代策略 | 如需隐藏 SNI,考虑以下方案替代 ECH:双 TLS(外层正常握手 + 内层加密握手)、CDN 前置(通过 CDN 节点中转流量)、域名前置(HTTP Host 与 SNI 不一致,但现代 CDN 已基本封堵) |
| ECH GREASE | Chrome 发送 ECH GREASE 扩展(即使没有真实 ECH 配置)。如果模板模拟 Chrome 但缺少 ECH GREASE,也是指纹偏差 |
TCP/IP 栈指纹是 TLS 指纹之外的第二维度,审查系统通过交叉验证两层指纹的一致性来检测伪装。
| 检查项 | 说明 |
|---|---|
| 初始 TTL 值 | TTL 值可以推断操作系统和距离。常见初始值:Linux=64, Windows=128, macOS=64。如果 TLS 指纹声称是 Windows Chrome 但 TTL 初始值显示 Linux(64 或因路由跳数减少后的值),交叉矛盾暴露伪装。需考虑网络路径上的跳数衰减 |
| TCP 窗口大小 | 初始窗口大小是否与声称的操作系统一致?Linux 默认约 64240 字节,Windows 默认约 65535 字节。异常的窗口大小是 OS 指纹 |
| TCP 选项顺序 | TCP 选项(MSS、Window Scale、SACK Permitted、Timestamp、NOP)的排列顺序和值是否与目标操作系统一致?Linux 和 Windows 的 TCP 选项顺序不同。例如 Linux 通常按 MSS → SACK → Timestamp → NOP → Window Scale 排序 |
| TCP 选项值 | MSS 值、Window Scale 值、SACK 最大数量等选项值是否与目标操作系统一致?自定义值是 OS 指纹 |
| IP 层特征 | IP 头中的 Don't Fragment(DF)位设置、TOS/DSCP 字段、IP ID 生成策略(递增、随机、零)是否与目标行为一致?不同 OS 的 IP ID 生成策略不同 |
| QUIC/UDP 共存 | 如果服务端同时监听 TCP 443 和 UDP 443(QUIC),UDP 上的 QUIC 握手是否也经过合规处理?审查系统会同时检查 TCP 和 UDP 端口。QUIC ClientHello 同样有指纹 |
| 跨层一致性 | 所有层次的指纹必须指向同一个操作系统/浏览器组合。TLS 扩展顺序模拟 Chrome/Windows,但 TCP 选项顺序和 TTL 暴露了 Linux 内核——这种矛盾是致命的 |
TLS 记录层是握手数据和应用数据的实际传输载体,记录层的构造方式是 TLS 库指纹。
| 检查项 | 说明 |
|---|---|
| 记录版本号 | TLS 记录头的 legacy_record_version 应为 0x0301(TLS 1.0)或 0x0303(TLS 1.2)。BoringSSL 始终使用 0x0303,OpenSSL 在握手阶段可能使用 0x0301。不得使用 0x0300 或其他非标准值 |
| content_type 正确性 | ApplicationData 记录的 content_type 必须为 0x17,Alert 为 0x15,Handshake 为 0x16,ChangeCipherSpec 为 0x14。加密后的记录外部 content_type 必须为 0x17(ApplicationData),即使内部是 Handshake 或 Alert |
| 记录长度合规 | 单条 TLS 记录有效载荷不得超过 2^14 + 256 字节(TLS 1.3 的 2^14 明文上限 + 256 字节 AEAD 标签/填充空间)。超长记录是协议违规 |
| 零填充剥离 | TLS 1.3 中,加密记录的内部明文末尾包含零填充字节 + 真实的 content_type 字节。剥离逻辑必须从末尾向前扫描找到第一个非零字节作为 content_type。剥离错误会导致数据损坏或 content_type 解析错误 |
| 记录分片策略 | TLS 记录如何分片是 TLS 库的指纹。BoringSSL 和 OpenSSL 在大数据分片上的行为有差异(如 Certificate 消息是否拆分为多条记录)。记录大小应与目标实现一致 |
| 空记录处理 | TLS 1.3 禁止发送零长度的 ApplicationData 记录。发送空记录是协议违规,也是实现缺陷的标志 |
| 记录边界时机 | 握手消息与 CCS 记录之间的记录边界是否与标准实现一致?不恰当的记录合并(如将 CCS 和 Finished 放在同一记录中)是异常 |
多个伪装方案可能共存于同一服务端口,方案之间的指纹隔离至关重要。
| 检查项 | 说明 |
|---|---|
| 方案间无泄漏 | 当 SNI 匹配方案 A 但实际走方案 B 时,方案 A 的特征不得泄漏到方案 B 的流量中。方案切换必须是干净的,不得残留前一方案的协议特征 |
| 非认证流量处理 | 非认证客户端的流量必须被完整转发到真实目标,不丢弃任何字节。丢弃或修改非认证流量字节会导致协议违规或指纹异常 |
| CCS 记录处理 | ChangeCipherSpec 兼容记录必须正确处理。TLS 1.3 中 CCS 仅用于中间件兼容性,代理必须正确透传或模拟 CCS 记录,不得吞没或重复 |
| 错误隔离 | 一个方案的解析错误不得影响另一个方案的判断。方案 A 解析失败后回退到方案 B 时,读取的缓冲区数据必须完整保留并传递给方案 B |
| 缓冲区边界 | 多方案共用预读缓冲区时,每个方案只应消耗自己需要的数据,不得多读或少读。缓冲区偏移量在方案切换时必须正确重置 |
| 时序隔离 | 不同方案的响应时序不得泄漏方案类型。例如方案 A 的响应延迟为 50ms,方案 B 的响应延迟为 200ms,时序差异本身就是指纹 |
审计执行流程、所有禁止/正确的代码模式对照、指纹模板维护策略详见 anti-patterns.md。
crypto-audit 覆盖了本 skill 未深入探讨的证书字段完整性(CN/SAN 与 SNI 匹配、签名算法选择、有效期合理性、序列号随机性)、密钥交换安全性(X25519 低阶点检测)、常量时间操作维度leak-audit 覆盖了本 skill 未深入探讨的 TLS Alert 描述码指纹(BoringSSL vs OpenSSL 行为差异可被 JA4S 检测)、HTTP 错误响应格式指纹、部署规模追踪维度probe-audit 覆盖了本 skill 未深入探讨的 TLS 握手后应用层行为探测、多阶段探针响应一致性、回落机制形式化安全维度security-audit 提供了安全审计 skills 的编排指南,确定修改特定代码时应按何种顺序执行哪些审计