CC攻击中伪造请求头是最常见也最让运维头疼的对抗手段之一。攻击者不再使用明显的固定UA或者空Referer,而是通过随机化User-Agent、伪造X-Forwarded-For、模拟真实浏览器Accept、Accept-Language甚至Cookie特征,让请求看起来和正常用户几乎一致。单纯依靠IP频率限制或者简单的UA黑名单基本失效,因为攻击流量在单IP维度上可能并不突出,但整体请求量却能把源站资源耗尽。识别这类攻击的核心思路不是“找出哪个请求一定是假的”,而是通过多维特征组合、行为基线比对和统计异常检测,把伪造请求头暴露出的不一致性放大。

伪造请求头攻击的典型特征

伪造请求头攻击通常会在几个维度上露出破绽。第一是请求头之间的逻辑矛盾,例如UA声明为Chrome 120但Accept-Language却是空值,或者UA是移动端Safari但Sec-CH-UA-Mobile提示为桌面端。第二是请求头顺序异常,真实浏览器的请求头顺序相对固定,而多数脚本工具生成的请求头顺序混乱或完全按字典排序。第三是TLS指纹与UA不匹配,例如JA3指纹显示为Python的底层库,但UA伪装成Chrome。第四是HTTP版本与请求头组合不协调,比如HTTP/1.1却携带了HTTP/2才常见的伪头字段。第五是Cookie与UA的关联性断裂,比如Cookie中的会话标识显示用户此前使用Firefox,但当前请求UA突然变成Edge,且没有正常的登录态切换逻辑。

基于请求头顺序的识别方法

真实浏览器的请求头顺序在同一个大版本内基本保持稳定。以Chrome为例,其请求头顺序通常为Host、Connection、Content-Length、sec-ch-ua、sec-ch-ua-mobile、User-Agent、Accept、Accept-Encoding、Accept-Language、Cookie。而使用requests、curl或自定义脚本发送的请求,头顺序往往取决于代码中字典的插入顺序,或者完全随机。可以在Nginx或应用层记录每个请求的头部顺序指纹,将头名称序列做哈希后与已知浏览器基线比对。对于顺序偏离基线过大的请求,直接标记为高风险。需要注意的是,部分代理或CDN会重排请求头,因此该方法更适合在源站直接观测,或者与CDN协商保留原始头顺序。

利用TLS指纹辅助判断

TLS握手阶段的JA3指纹是识别伪造UA的强特征。攻击者可以轻易修改HTTP头中的User-Agent,但很难同时修改底层TLS库的握手特征。例如Python requests默认的JA3指纹与真实Chrome完全不同,即使UA写成Chrome也无法掩盖。可以在负载均衡或反向代理层启用JA3指纹采集,将指纹与UA进行关联分析。当UA声明为Chrome但JA3指纹指向Go-http-client、Python-urllib或OpenSSL默认配置时,基本可以判定为伪造请求。对于高频访问的IP,如果其JA3指纹在短时间内频繁变化,也说明请求源可能使用了多种脚本工具轮换。

请求头组合逻辑校验

攻击者伪造请求头时往往只关注UA和X-Forwarded-For,忽略其他字段之间的逻辑一致性。可以建立一套校验规则,例如:UA为移动端时,Sec-CH-UA-Mobile应为?1,Accept中应包含text/html且Accept-Encoding通常包含br;UA为Chrome 100以上时,Sec-CH-UA应存在且包含Chromium版本号;Accept-Language为空但Cookie中存在用户偏好语言时,说明请求头被工具删减;X-Requested-With存在且为XMLHttpRequest时,Referer不应为空。这些规则不需要穷举所有情况,只需覆盖攻击工具最常见的疏漏点。对于校验失败的请求,可以进入验证流程或直接降低其优先级。

行为基线比对与统计异常检测

伪造请求头攻击通常由自动化工具发起,其请求行为与真实用户存在统计差异。可以针对每个IP或每个会话建立行为基线,统计请求间隔分布、URL访问路径深度、资源请求比例、Cookie携带率、Referer多样性等指标。真实用户的请求间隔呈现指数分布且存在随机波动,而脚本攻击往往间隔过于均匀或呈现固定节奏。真实用户在访问页面后会请求CSS、JS、图片等静态资源,而纯接口型攻击只请求动态URL。真实用户的Referer会随着浏览路径变化,而伪造请求的Referer要么固定不变,要么完全缺失。当某个来源的多个统计指标同时偏离基线时,即使其请求头看起来正常,也应触发风控。

Cookie与会话关联性验证

Cookie是识别伪造请求头的重要锚点。攻击者为了绕过频率限制,可能不携带Cookie或使用随机生成的Cookie。真实用户在首次访问时会被分配会话标识,后续请求会持续携带该标识。如果某个IP在短时间内发起了大量请求,但Cookie缺失率超过90%,或者Cookie值频繁变化且没有登录态切换的合理逻辑,就需要重点排查。更深入的验证方式是检查Cookie中的设备指纹、登录态与UA的关联性。例如Cookie中记录了用户上次登录时使用的UA为Safari,但当前请求UA为Chrome且没有重新登录记录,这种矛盾说明请求头可能被伪造或会话被劫持。

基于机器学习的实时识别

当攻击规模较大且伪造手法多变时,规则引擎可能跟不上变化速度。此时可以引入轻量级机器学习模型,将请求头的各项特征向量化后输入模型进行实时分类。特征可以包括UA长度、UA是否在已知浏览器列表中、头字段数量、头顺序哈希、TLS指纹、Cookie长度、Referer域名是否与Host一致、Accept-Language是否为空、Sec-CH-UA是否存在等。训练数据可以来自历史攻击样本和正常流量样本。模型不需要太复杂,随机森林或梯度提升树即可达到较好的识别效果。关键是要定期用新样本更新模型,防止攻击者针对模型特征进行规避。模型输出风险分数后,与规则引擎结果融合,对高风险请求执行验证码、JS挑战或直接丢弃。

防御部署建议

在实际部署中,建议将识别能力分层落地。边缘层做粗筛,利用TLS指纹和请求头顺序快速过滤明显伪造的请求,降低源站压力。应用层做细筛,结合Cookie会话、行为基线和业务逻辑进行二次判断。对于无法确定但可疑的请求,引入验证码或JS挑战,让真实用户无感通过,让自动化工具付出成本。同时要建立攻击样本库,将每次确认的攻击请求头特征沉淀下来,用于后续规则优化和模型训练。日志记录方面,务必保留完整的请求头原始信息,包括头顺序和TLS指纹,否则事后分析时很多特征已经丢失。

# Nginx示例:记录请求头顺序和JA3指纹(需配合第三方模块)
log_format forensic '$remote_addr [$time_local] "$request" '
                    '$status $body_bytes_sent '
                    'header_order=$http_header_order '
                    'ja3=$ssl_ja3 '
                    'ua=$http_user_agent';

需要强调的是,任何单一识别方法都存在误判可能,实际效果取决于多维特征的组合使用。伪造请求头攻击的对抗本质上是成本对抗,当攻击者需要同时伪造UA、TLS指纹、请求头顺序、Cookie关联性和行为模式时,其攻击成本会大幅上升,而防御方的识别准确率也会显著提高。持续监控和动态调整策略,比一次性部署一套固定规则更有效。