适用于: ✔️ Front Door Premium
Azure Web 应用程序防火墙 (WAF)在 Azure Front Door 上可以将请求与客户端的 TLS 指纹进行匹配。 TLS 指纹描述了客户端如何协商 TLS 连接,因此可作为识别会轮换 IP 地址或伪造请求头的自动化流量的有用信号。
Azure Front Door WAF 使用 JA4 指纹识别标准。 你可以通过自定义规则使用客户端指纹匹配,将匹配变量 JA4 设置为,操作符设置为 ClientFingerprint。
客户端指纹匹配在攻击者频繁更换IP地址但仍然使用相同客户端软件的情况下最有价值。 由于指纹是从TLS握手中获得的,而不是请求内容,因此比IP地址、 User-Agent 头部或cookie更难伪造。
客户指纹匹配的运作方式
当客户端打开 Azure Front Door 的 TLS 连接时,会发送一条 TLS 客户端 Hello 消息,宣传其支持的 TLS 版本、密码套件、扩展、签名算法和协商应用协议。 这些值的具体组合和顺序由客户端的 TLS 库和配置决定,而非用户。
Azure Front Door 会从客户端 Hello 计算 JA4 指纹,并将其与自定义规则中的数值进行比较。 如果指纹匹配你指定的某个值,匹配条件会被评估为真,规则的操作就会被执行。
使用相同TLS协议栈、版本和配置的两个客户端会产生相同的指纹。 这种行为使得指纹识别在对抗分布式自动化时有效,也是编写规则时需要考虑的主要因素。 请参阅注意事项。
JA4指纹格式
JA4指纹是一串36个字符的字符串,由三个带下划线分隔的部分组成:
t13d0512h2_cfafc68803c7_6bebaf5329ac
| 部件 | Example | DESCRIPTION |
|---|---|---|
JA4_a |
t13d0512h2 |
人类可读的前缀。 传输(q 表示 TCP,13 表示 QUIC)、TLS 版本(d 表示 TLS 1.3)、SNI 是域名(i)还是 IP 地址(h2)、密码套件数量、扩展数量,以及第一个 ALPN 值(t)。 |
JA4_b |
cfafc68803c7 |
排序后的密码套件列表的一个 12 字符截断哈希。 |
JA4_c |
6bebaf5329ac |
扩展和签名算法的排序列表的一个 12 个字符的截断哈希值。 |
由于 JA4_a 指纹是人类可读的,你可以通过指纹来了解客户的形状,然后再决定是否采取行动。 例如,一个在TLS 1.3上宣传很少密码和扩展的客户端,更可能是脚本化的HTTP客户端,而不是浏览器。
配置客户端指纹匹配条件
客户端指纹匹配条件使用以下设置。
| 设置 | Value |
|---|---|
| 匹配变量 | JA4 |
| Operator | ClientFingerprint |
| 匹配值 | 一条或多条JA4指纹字符串 |
| 否定条件 | Optional. 将其设置为 true,以匹配除你列出的指纹之外的所有指纹。 |
匹配值作为精确字符串进行比较。
ClientFingerprint 运算符不支持部分指纹、通配符和正则表达式。 如果你想按指纹的一部分进行匹配,请获取你关心的完整值,并将它们逐项列出。
在您的流量中查找指纹
Azure Front Door 在 clientJA4FingerPrint_s 日志字段中记录每个请求计算得出的 JA4 指纹。 使用此字段可在编写对这些指纹生效的规则之前,发现流量中存在哪些指纹。
首先,请执行以下操作:
- 在您的 Azure Front Door 配置文件上启用 WAF 日志。 有关详细信息,请参阅 Azure Web 应用程序防火墙监视和日志记录。
- 查询你的日志,对将流量送往你调查路径的指纹进行排序。
- 将驱动滥用流量的指纹与你合法用户发送的指纹进行比较。
- 将恶意指纹添加到带有
Block操作的规则中,或者将已知安全的指纹添加到Allow规则中。
以下Kusto查询列出了过去一天中最常见的指纹,以及每种指纹使用了多少不同的客户端IP地址:
AzureDiagnostics
| where Category == "FrontdoorWebApplicationFirewallLog"
| where TimeGenerated > ago(1d)
| summarize
Requests = count(),
DistinctClientIPs = dcount(clientIP_s)
by clientJA4FingerPrint_s
| order by Requests desc
指纹如果涉及大量不同IP地址的请求量很大,是值得调查的有力对象。 这种模式是分布式自动化的特征,该模式在重复使用一个客户端栈的同时轮换地址。
在屏蔽某个指纹之前,务必先确认你的正常用户中没有相当一部分在共用该指纹。 如果不确定,请先使用 Log 操作部署该规则,并查看它原本会匹配哪些内容。
示例
屏蔽已知的机器人指纹
假设你识别到一个导致一波脚本流量的单个 JA4 指纹。 以下自定义规则阻止了它:
{
"name": "BlockKnownBotFingerprint",
"priority": 10,
"ruleType": "MatchRule",
"matchConditions": [
{
"matchVariable": "JA4",
"operator": "ClientFingerprint",
"negateCondition": false,
"matchValue": [
"t13d0512h2_cfafc68803c7_6bebaf5329ac"
]
}
],
"action": "Block"
}
用允许列表保护敏感路径
你可以不阻挡已知不良指纹,只需允许已知良好指纹进入敏感路径。 以下规则会阻止任何发往 /api/checkout 且其指纹不在批准列表中的请求。 该 negateCondition 属性会反转指纹匹配,且规则匹配必须满足这两个条件。
{
"name": "RestrictCheckoutToApprovedClients",
"priority": 20,
"ruleType": "MatchRule",
"matchConditions": [
{
"matchVariable": "RequestUri",
"operator": "Contains",
"negateCondition": false,
"matchValue": [
"/api/checkout"
]
},
{
"matchVariable": "JA4",
"operator": "ClientFingerprint",
"negateCondition": true,
"matchValue": [
"t13d1516h2_8daaf6152771_02713d6af862",
"t13d1517h2_8daaf6152771_b0da82dd1658"
]
}
],
"action": "Block"
}
请仔细使用这个图案。 允许列表会拦截所有你未预料到的客户端协议栈,包括那些采用了变更后 TLS 配置的新浏览器版本。 先使用 Log 动作运行该规则,并查看它原本会拦截哪些内容。
挑战可疑指纹,而不是屏蔽它
如果你不够自信直接屏蔽指纹,可以发起JavaScript挑战。 合法浏览器能透明地解决这一挑战,而大多数脚本客户端则失败。
{
"name": "ChallengeSuspiciousFingerprint",
"priority": 30,
"ruleType": "MatchRule",
"matchConditions": [
{
"matchVariable": "JA4",
"operator": "ClientFingerprint",
"negateCondition": false,
"matchValue": [
"t13d0512h2_cfafc68803c7_6bebaf5329ac"
]
}
],
"action": "JSChallenge"
}
Considerations
在制定客户指纹规则时,请记住以下几点:
- 指纹用于识别客户端栈,而非用户。 每个在同一平台上运行相同浏览器的用户都会共享一个指纹。 屏蔽普通浏览器指纹会屏蔽大量合法用户。 指纹最适合用于识别特殊或专门设计的客户。
- 客户变更时,指纹也随之改变。 浏览器更新、TLS库更新和配置更改都会产生新的指纹。 将指纹规则视为需要定期重新评估的对象,并在你屏蔽某个指纹后,监测流量是否转向新的指纹。
- 攻击者可以更改指纹。 指纹识别会提高自动化成本,但有决心的攻击者可以修改他们的TLS客户端。 将指纹规则作为其中一层,并与速率限制、托管规则集和机器人防护结合使用,而不是将其作为唯一的控制措施。
- 从检测模式开始。 使用
Block操作部署新的指纹规则,或者将 WAF 策略设置为检测模式,并在切换到Log之前查看日志。 - 结合条件以减少爆炸半径。 将指纹条件与URI路径、主机或请求方法条件配对,可以将规则限制在你打算影响的流量范围内。