Burp Suite 里的 Sequencer,我平时更愿意把它叫作“令牌体检机”。它不负责找注入点,也不负责爆破,它只干一件事:判断你手里这串会话令牌、CSRF 令牌、密码重置链接里的那串随机字符,到底是真随机,还是“看着像随机”。做 Web 安全测试的人,只要碰过登录态相关的评估,几乎都会被问到一个问题——这串 token 能不能被猜到?凭感觉回答是很危险的,Sequencer 就是把这个“感觉”变成数字的工具。它能采集成百上千个令牌样本,然后从字符分布、比特分布、熵值、游程等多个角度给出统计学结论,最后把结果浓缩成一个“Excellent / Very good / Good / Poor”的评级。这篇文章我打算把 Sequencer 的定位、原理、完整实操流程、结果解读、参数计算和踩过的坑一次讲透,适合刚接触 Web 安全测试、看到一堆熵值名词发懵的新手,也适合已经会用但一直没搞懂“有效熵”怎么算的老手。读完你至少能做到:知道什么场景该开它,知道样本要采多少,知道结果里哪些数字能写进报告,哪些只能自己心里有数。
1. 先搞清楚 Sequencer 到底在解决什么问题
1.1 一个令牌被猜中意味着什么
登录成功后服务端发给你一个 Session ID,之后每次请求带上它,服务端就认你是你。这个机制成立的前提是:别人猜不到你的 Session ID。如果生成算法足够弱,比如用了可预测的伪随机数、用了时间戳拼接、用了自增 ID 做混淆,攻击者只要拿到自己的一两个 ID,就有可能推算出一批别人的有效 ID,直接跳过密码登录。这一类问题在评估里被归类为“会话令牌生成不安全”,危害等级通常不低,因为它一旦成立,就是批量接管账号。
问题在于,这类缺陷很难用眼睛看出来。一串a3f8c91e7b2d4065摆在面前,你凭什么说它弱?凭长度?凭看着像不像乱码?这些都不靠谱。你需要的是一批样本,然后回答三个具体的问题:这串字符用了多大的字符集?每一位上的分布是否均匀?整体熵值够不够抵抗暴力枚举?Sequencer 干的就是这件事,它把“看起来随机”这种主观判断,换成可以复现的统计结果。
1.2 Sequencer 的定位:它是体检设备,不是漏洞扫描器
这一点必须先说清楚,否则很容易用错。Sequencer 不会主动发请求去“攻击”什么,它只是采集样本、做统计。它给不出“存在漏洞”这种结论,只能给出“这串令牌的随机性水平偏低”这种观察。这两者的区别很大:随机性偏低是一个风险信号,但能不能真正被利用,还要看令牌的有效期、是否绑定其他因素、是否有频率限制、是否与服务端状态关联。
我见过有人在报告里直接写“Sequencer 检测到令牌熵值不足,存在会话劫持漏洞”,这个表述是有问题的。正确的写法应该是描述观察到的统计特征,再结合业务上下文说明潜在影响。举个反例:某系统令牌只有 32 位,熵值确实不高,但它绑定了一次性校验码和客户端指纹,实际可利用性接近零。这种情况下你把危害写得很高,复核的时候是要被打回来的。
所以我的用法是:Sequencer 用来做“初筛”和“取证”。初筛是快速判断这串令牌值不值得深挖,取证是在报告里提供量化的支撑材料。这两个用途都不需要它给结论,结论是你自己结合上下文下的。
1.3 哪些令牌值得送进去测
不是所有看起来像随机串的东西都适合用 Sequencer。我一般按下面这个清单来判断:
| 令牌类型 | 是否适合 | 说明 |
|---|---|---|
| 会话 Cookie(Session ID) | 非常适合 | 最常见的测试对象,样本易采集 |
| CSRF Token | 适合 | 注意它可能与会话绑定,需固定会话采集 |
| 密码重置令牌 | 适合 | 通常出现在邮件链接里,需从响应中提取 |
| API Key / Access Token | 适合 | 注意区分前缀固定部分与随机部分 |
| 图形验证码 | 不适合 | 字符集受限、有语义、有效期极短 |
| 短数字验证码(6 位) | 不适合 | 长度太短,统计意义有限,应测频率限制 |
| 自增 ID 混淆后的值 | 视情况 | 需先判断是否可解码,再决定测不测 |
| JWT 的签名段 | 不适合 | 签名由密钥决定,不靠随机性 |
这里有个容易忽略的点:很多令牌是“前缀 + 随机段”的组合,比如sess_开头后面跟 40 个字符。如果你整串扔进去,固定前缀会严重拉低统计结果,让本来合格的令牌看起来很差。Sequencer 提供了自定义提取位置的功能,这个后面会详细讲怎么配。
2. 核心原理拆解:熵值到底怎么来的
2.1 字符级分析与比特级分析的区别
Sequencer 的分析分成两个层面,很多人只看总评就关掉了,其实这两层信息量差别很大,值得分别看。
字符级分析把令牌当成一串字符,统计每个位置上的字符分布情况,以及整体的字符使用频率。它的产出是“每个字符平均携带多少比特信息”,也就是每字符熵。举例来说,如果令牌全长只用小写字母加数字共 36 个字符,且分布均匀,那么每字符熵接近 log2(36) ≈ 5.17 比特。如果实际测出来只有 3.2 比特,说明分布明显偏斜,某些字符出现得特别频繁,有效随机空间被压缩了。
比特级分析则把令牌转换成二进制流,看每一位上 0 和 1 的比例是否接近 1:1,以及相邻位之间是否存在相关性。这个层面的测试更严格,也更容易暴露出“伪随机数生成器质量差”的问题。有些令牌字符层面看着挺均匀,但转成比特后发现某些位几乎是固定的,这种情况下比特级分析会直接告警。我遇到过一次,某系统的令牌转成二进制后,每个字节的最高位恒为 0,意味着实际只用了 7 位,虽然字符集看着是完整的十六进制。
2.2 香农熵、有效熵、最小熵三个数字的分工
结果页面上最显眼的是几个熵值,我第一次看的时候也是一头雾水,后来才理清它们的关系。
香农熵(Shannon entropy per character)衡量的是单个字符位置上的平均不确定性。计算公式是 H = -Σ p(x) log2 p(x),p(x) 是字符 x 在样本中出现的频率。这个值越高说明字符分布越均匀。上限取决于字符集大小,用 62 个字符的话理论上限是 5.95,用 16 个十六进制字符理论上限是 4.0。
有效熵(Effective entropy)是香农熵乘以令牌长度,代表整串令牌的总信息量。举个例子,某令牌长度 32 位,每字符熵实测 3.9,那么有效熵约 124.8 比特。这个数字才是判断“能不能被暴力枚举”的关键。124 比特意味着即使攻击者每秒尝试 10 亿次,穷举完成也要远超宇宙年龄,实际不可行。
最小熵(Min entropy)更保守,它取的是分布中最坏情况下的下界,公式是 -log2(p_max),p_max 是出现频率最高的字符的概率。这个值对偏斜特别敏感,能揭示“平均看着还行,但某个字符出现得异常多”的情况。做严谨评估的时候我更看重最小熵,因为它不给乐观估计。
下面这张表是我常用的对照,帮助快速判断量级:
| 有效熵(比特) | 直观含义 | 处理建议 |
|---|---|---|
| < 40 | 理论上可枚举 | 重点关注,考虑风险 |
| 40 - 64 | 弱,取决于速率限制 | 结合业务上下文评估 |
| 64 - 96 | 中等 | 一般可接受,看场景 |
| 96 - 128 | 良好 | 符合常见实践 |
| > 128 | 优秀 | 基本无枚举风险 |
这个表只是经验参照,不是标准。真正写报告的时候要把具体数字、样本量、测试时间都写上,让别人能复现。
2.3 FIPS 140-2 那套测试在跑什么
Sequencer 里还有一组测试,名字看着很唬人,实际是几个经典的随机性检验,源于一份早期的随机数发生器评估规范。它们把样本转成连续的比特流,然后跑五项检查:
- 单比特测试(Monobit):统计 0 和 1 的总数是否接近各占一半,允许区间大致在 9725 到 10275 之间(针对 20000 比特样本)。
- 扑克测试(Poker):把比特流切成 4 位一组,检查 16 种组合出现次数是否符合均匀分布,用卡方统计量判断。
- 游程测试(Runs):统计连续相同比特的长度分布,长度 1、2、3、4、5、6 及以上各有对应的期望区间。
- 长游程测试(Long Runs):检查是否出现超长的连续相同比特,超过一定长度就判定异常。
- 近似熵测试(Approximate Entropy):检查比特序列中重复模式的规律性。
这几项测试的价值在于,它们能抓出一些熵值看不出来的问题。比如某个生成器每 8 位里必定有一个 1,整体字符分布可能还凑合,但游程测试会立刻报异常。反过来说,这几项全部通过也不代表安全,只能说“没有明显的统计规律”。这个边界要守住,别把通过 FIPS 测试当成安全认证。
2.4 样本量:为什么采 100 个等于没测
这是新手最容易犯的错。Sequencer 采了几十个样本就点分析,跳出来一个“Excellent”,然后心满意足地关掉了。这个结论基本没有参考价值。
原因很直白:统计推断需要足够的样本量才能收敛。你想想,如果我只有 20 个样本,每个样本 32 个字符,总共才 640 个字符观测值,分摊到 62 个可能字符上,平均每个字符才被观测到 10 次左右。在这个量级下,随机波动完全可以掩盖真实的分布偏斜。
我的经验标准是:样本数不少于令牌长度的 300 倍,且绝对值不低于 10000。比如测一个 32 位的令牌,至少采 9600 个,实际我会直接设成 20000 个。这个量级下统计结果才稳定,重复跑两次结论不会漂。执行条件允许的话,把采集时间安排在业务低峰期,避免采集过程中被限流打断。
采集耗时不长,Sequencer 支持并发请求,我一般开 20 到 30 个线程,20000 个样本大概几分钟就能跑完。但要留意目标系统的承受能力,别把一个生产环境的服务打挂,这就从测试变成事故了。
3. 上手实操:一次完整的采集与分析
3.1 定位令牌位置并送入 Sequencer
实操第一步是找到令牌在哪个响应里。以最常见的会话 Cookie 为例,在代理历史里找到登录成功那个请求,看响应头里的Set-Cookie。假设拿到的是SESSIONID=9f2b...这样的形式。
接下来的操作路径是:在代理历史里选中这个请求,右键,找到送到 Sequencer 的选项。注意送进去的应该是“触发令牌生成的那个请求”,不是携带令牌的后续请求,否则采集时会一直拿到同一个值。
进入 Sequencer 界面后,先看“令牌位置”这个配置区。默认情况下它会尝试从响应里自动识别候选令牌,通常能从 Set-Cookie 里挑出来。如果识别得不对,需要手动配置:
- 选择“自定义位置”模式,界面上会显示响应原文。
- 用鼠标选中响应里令牌值的起止位置,注意不要选中 Cookie 名和等号,只选值本身。
- 如果令牌在响应体里(比如 JSON 返回),同样手动框选,或者用正则表达式匹配。
- 有多个令牌要测的话,可以在 Cookie 下拉列表里单独选择某个 Cookie。
这一步的精度直接影响结果可信度,我踩过一次坑:手动框选时多选了一个引号,导致字符集里凭空多出一个字符,每字符熵算出来偏高,白白浪费了一轮采集。
配置好之后先点一次单次请求测试,确认采样到的值符合预期,再开始批量采集。
3.2 实时采集的关键参数怎么调
实时采集面板上有一组选项,看着杂,实际关键的就几个:
- 并发线程数:控制同时发出多少请求。默认值偏低,我一般调到 20 到 30。太高容易被目标限流或触发防护。
- 请求间隔:每个线程两次请求之间的等待毫秒数。目标响应慢或者有限流迹象时,把间隔调大,宁可慢也别被打断。
- 跟随重定向:如果触发令牌的请求会重定向,必须开启,否则采到的可能是重定向响应,里面没有令牌。
- 自动暂停条件:可以设置“连续 N 次拿到相同令牌时暂停”,这个很有用,能及时发现令牌位置配错或者服务端复用了缓存。
采集启动后,界面上会实时显示样本数、令牌长度、当前估算的熵值。这里有个实用技巧:观察熵值随样本增长的收敛曲线。如果采到 5000 个样本时熵值还在明显漂移,说明样本量不够;如果到 10000 个基本平了,就可以停了。这个判断方法比死记数字更靠谱。
另外要注意,Sequencer 默认会丢弃重复的令牌样本。这个设计是合理的,因为重复值本身说明不了随机性,反而会污染统计。但也要留个心眼:如果丢弃率高得离谱,比如采了 20000 次只剩 3000 个不重复的,那说明令牌空间实际很小,这本身就是一个重要发现。
3.3 手动导入样本的两种姿势
有些场景下实时采集走不通:令牌只发一次、有严格频率限制、或者你已经有一批现成的令牌样本。这时候用手动导入。
第一种方式是直接粘贴。把令牌样本按行粘贴到文本框里,一行一个,然后点分析。这种方式适合样本量小、来源零散的情况,我一般只在做快速验证时用。
第二种方式是导入文件。先在本地把样本整理成文本,每个令牌一行,用文件选择器加载。这种方式能处理几万条的大样本,而且样本可以来自日志、数据库导出、或者你自己写的脚本采集结果。我做过一次评估,目标系统的令牌隐藏在加密响应里,只能通过业务渠道批量导出,就是用这种方式完成的:先用脚本采集导出,再整理成一行一个的格式,最后导入 Sequencer 分析。
手动导入有个硬性要求:样本必须是一行一个,不能有空行,不能带引号,不能带前缀标签。我见过有人在每行前面加了序号,结果所有令牌都被识别成以数字开头,字符集分析直接废掉。导入前用文本编辑器做一次批量替换,把多余字符清干净。
3.4 读结果:从总览到分项,别只看那个总评
点击分析后,出来的是好几块内容,我按重要性排序说。
总览区给出 Overall result 评级和几个核心数字。这个评级是工具根据一套内部阈值给的,可以参考,但别当成唯一依据。我更关注它下面那几个具体熵值。
字符分析区显示字符集识别结果和各字符的出现频率分布图。这里能看出两件事:一是实际使用的字符集大小,二是分布是否均匀。如果图上明显有几个柱子特别高,说明这些字符被过度使用,有效熵会打折。我遇到过一种情况:令牌声称是随机十六进制,但0和f的出现频率明显偏高,进一步排查发现生成器用了取模运算,存在轻微的分布偏差。
比特分析区展示每一位上 0/1 的比例,通常以条形图或表格呈现。理想情况下每个位置的 0/1 比例都接近 50%。如果有多个位置的偏差超过几个百分点,就要警惕了。这里我建议导出结果保存,方便和后续版本的令牌做对比。
显著性检验区会让你设置显著性水平,默认通常是最常用的那一档。它的作用是对每个字符位置做拟合检验,判断该位置的分布是否显著偏离均匀。如果大量位置被标记为不随机,那就是明确信号。
还有一个容易被忽视的地方:结果里的令牌长度。有些系统会动态变化令牌长度,采集过程中如果长度不一致,Sequencer 会按最短的来处理,导致熵值计算偏低。分析前扫一眼长度分布,不一致的话要单独处理。
4. 参数计算与自定义校验脚本
4.1 手算一遍理想值,你才知道结果偏不偏
做评估的时候,报告里写“熵值偏低”是不够的,得说清楚低多少、理论上限是多少。这就需要自己会算。
举个具体例子。假设某令牌是 32 位十六进制字符串。十六进制字符集大小是 16,理想情况下每字符熵 = log2(16) = 4.0 比特,那么整串的理想有效熵 = 32 × 4.0 = 128 比特。这是理论上限,实际测出来通常会略低,因为样本有限、分布有微小波动。
如果实测每字符熵只有 3.1,那有效熵 = 32 × 3.1 = 99.2 比特,比理想值少了约 22%。这个差距意味着什么?意味着实际的有效搜索空间从 2^128 降到了 2^99。虽然 2^99 依然很大,但缩水幅度值得在报告里提出来。
再举一个字母数字混合的例子。字符集 62,每字符理想熵 = log2(62) ≈ 5.954 比特。如果令牌长度是 20,理想有效熵 = 119 比特。这个数字对很多场景是够的。但如果实测每字符熵只有 4.5,有效熵就掉到 90 比特,就要结合业务场景判断了。
这里有个关键提醒:理论上限的计算要用实际观测到的字符集,不能用你假设的字符集。有些令牌号称 62 字符集,实际采集两万个样本后发现只出现了 38 个不同字符,那真实上限就是 log2(38) ≈ 5.25 比特,不是 5.95。这个差异会被很多人忽略。
4.2 用脚本自己复现一遍分析
Sequencer 的结果好用,但有时需要批量处理或者集成到自动化流程里,这时候自己写个脚本更灵活。下面这段代码是我常用的简化版,能算出每字符熵、有效熵和最小熵:
import math from collections import Counter def analyze_tokens(tokens): joined = "".join(tokens) total = len(joined) freq = Counter(joined) # 每字符香农熵 shannon = 0.0 for ch, cnt in freq.items(): p = cnt / total shannon -= p * math.log2(p) # 最小熵 p_max = max(freq.values()) / total min_entropy_per_char = -math.log2(p_max) # 理论每字符熵上限,基于实际出现的字符集 charset_size = len(freq) ideal_per_char = math.log2(charset_size) if charset_size > 1 else 0 avg_len = sum(len(t) for t in tokens) / len(tokens) return { "sample_count": len(tokens), "charset_size": charset_size, "avg_length": round(avg_len, 2), "shannon_per_char": round(shannon, 4), "min_entropy_per_char": round(min_entropy_per_char, 4), "ideal_per_char": round(ideal_per_char, 4), "effective_entropy": round(shannon * avg_len, 2), "effective_min_entropy": round(min_entropy_per_char * avg_len, 2), } # 示例:从文件读取,一行一个令牌 with open("tokens.txt", "r", encoding="utf-8") as f: tokens = [line.strip() for line in f if line.strip()] result = analyze_tokens(tokens) for k, v in result.items(): print(f"{k}: {v}")这段脚本的价值在于,你可以把它接在自己的采集脚本后面,形成“采集 → 分析 → 输出报告片段”的流水线。我在做批量评估的时候,一个目标可能有十几个令牌要测,手工一个个点太慢,用脚本几分钟就出一份汇总表。
要注意的是,这个脚本算的是字符级的统计,不涉及比特级的相关性分析。真要做完整评估,比特级的部分还是要看 Sequencer 的结果,或者自己补上比特流的相关性检验。
4.3 多轮采样对比,能发现单轮看不到的问题
单次采集的结果是有随机波动的。如果第一次测出来熵值偏低,不要急着下结论,换个时间再采一轮。我一般会采两到三轮,放在不同的时间段。
为什么要这么做?因为有些系统的令牌生成质量跟负载相关。低峰期用高质量随机源,高峰期为了性能降级成弱随机源。如果只在高峰期测,你会得出偏悲观的结论;只在低峰期测,又会漏掉问题。两轮对比一下,如果差异明显,那本身就是个值得记录的观察。
还有一种情况是令牌格式变更。系统升级后令牌长度从 24 位变成 32 位,但字符集从 62 缩到了 36,理论上限反而可能没提升多少。这时候多轮对比加上手算验证,就能说清楚变化到底有没有实质意义。
5. 踩坑记录与排查速查表
5.1 采集被污染,结果全废
这是我见过最高频的问题。表现是分析出来的熵值明显偏低,字符集乱七八糟,但目标系统实际上并没有那么差。原因通常有三种。
第一种是令牌位置配错。响应里有多处相似字符串,配到了错误的那一段,采到的是固定值或者半固定值。判断方法是看采集过程中“重复令牌比例”,如果超过九成都是重复的,基本可以确定配错了位置。
第二种是响应里混入了其他动态内容。有些接口返回的 JSON 里既有令牌也有时间戳、也有随机 ID,如果框选范围过大,把别的内容也带进去了,字符集和长度都会异常。解决方法是精确框选,或者用正则只匹配令牌那一段。
第三种是采集过程中会话状态变化。比如采集中途登录态过期,后续请求返回的是错误页,里面根本没有令牌,Sequencer 可能会把错误页里的某些字符串当成样本。这种情况的排查方式是导出样本列表人工扫一遍,看有没有明显不符合格式的条目。
注意:分析前一定要导出样本看几眼,这个动作花不了两分钟,能省掉大量返工。
5.2 令牌里混了时间戳,统计结果被拉偏
这是个经典陷阱。很多令牌的结构是“时间戳 + 随机段”,比如前 8 位是 Unix 时间戳的十六进制,后面 24 位才是随机值。整串拿去测,前 8 位的字符分布会严重偏斜(因为时间在短时间内几乎不变,高位字符基本固定),导致整体熵值被显著拉低。
处理办法是把令牌拆开测。只提取后面真正的随机段,单独分析。怎么确定哪部分是时间戳?把样本按时间排序,观察前几位的变化规律,如果是从左往右缓慢变化,基本可以确认。或者把值转成十进制,看看是不是落在合理的时间范围内。
我在一次评估里遇到过一个更隐蔽的变体:令牌的中间某一段是用户 ID 的哈希。这种情况下前后两段随机,中间一段对同一用户固定。如果只测单一用户的令牌,中间段会呈现明显的低熵特征。正确的做法是用多个不同账号分别采集,或者把令牌按位置切开,逐段分析。
5.3 常见问题速查表
| 现象 | 可能原因 | 排查动作 |
|---|---|---|
| 采集刚开始就大量重复 | 令牌位置配错 / 服务端缓存 | 检查框选范围,看响应是否被缓存 |
| 熵值随样本增加剧烈波动 | 样本量不足 | 增加到 10000 以上再观察 |
| 字符集比预期小很多 | 令牌有固定前缀被一起选入 | 精确框选,排除固定部分 |
| 比特分析显示某些位恒定 | 生成器只用部分位 | 转二进制验证,确认位数 |
| 分析报错提示样本格式问题 | 有空行、引号、序号前缀 | 文本清洗后重新导入 |
| 结果与手工计算差异大 | 令牌长度不一致 | 检查长度分布,分组处理 |
| 采集频繁中断 | 目标限流或防护触发 | 降低线程数,增加请求间隔 |
| 评级忽高忽低 | 单轮采样波动 | 多轮采样取一致结论 |
这张表我基本是贴在备忘里的,遇到异常先对一遍,能覆盖八成情况。剩下两成通常需要回到原始响应里逐条比对样本,虽然费时间,但比瞎猜靠谱。
6. Sequencer 的边界:它测不出来的东西
6.1 统计随机不等于不可预测
这是我最想强调的一点。Sequencer 做的所有测试,本质上都是在检验“这串数字看起来像不像独立均匀分布”。但密码学意义上的安全随机,要求的是“在不知道种子和算法的情况下无法预测下一个输出”。这两件事不等价。
举个极端的例子:某系统用了一个高质量的伪随机数生成器,但种子用的是当前秒级时间戳。生成出来的序列在统计上会非常漂亮,各种随机性检验全部通过,Sequencer 会给“Excellent”。但因为种子空间只有几十万种可能,攻击者只要知道大概的生成时间,就能穷举种子、复现整个序列。这种情况下,统计测试完全失效。
所以我的做法是:Sequencer 的结果只作为输入之一。真正的判断还要看令牌是否与会话强绑定、有效期多长、一次性还是可复用、有没有频率限制、生成逻辑是否能从其他响应里推断出来。这些信息 Sequencer 一概给不了。
6.2 令牌安全要和业务逻辑一起看
一个熵值 128 比特的令牌,如果服务端在校验时不比对用户身份,只是查“这个令牌是否存在”,那攻击者拿到任意一个有效令牌就能用。这种情况下,令牌本身的随机性再高也没意义,问题出在校验逻辑上。
反过来,一个熵值只有 60 比特的令牌,如果它五分钟过期、一次性使用、绑定 IP 和客户端指纹、失败三次就锁定,实际风险可能非常低。这也是为什么我在报告里从来不孤立地写熵值,一定要带上业务约束条件。
我整理过一个判断框架,评估令牌相关风险时按这个顺序过一遍:
- 令牌的熵值和长度是否达到场景要求;
- 令牌是否与用户身份强绑定,还是全局通用;
- 有效期多长,是否一次性;
- 是否有频率限制和异常检测;
- 生成算法是否可推断(比如是否含时间戳、是否含用户 ID);
- 传输和存储是否受保护。
Sequencer 只回答第 1 条,后面五条要靠抓包分析、逻辑测试和代码审计。把这条边界记清楚,能避免很多过度解读。
6.3 什么情况下干脆别用它
有些场景下用 Sequencer 是浪费时间。短数字验证码就是典型,六位数字总共一百万种组合,任何统计工具都会告诉你熵值极低,但这个结论毫无意义,因为这类验证码的防护手段是错误次数限制和有效期,不是随机性。你要测的是“连续错十次会不会锁”,不是“这串数字够不够随机”。
还有一种情况是令牌由服务端加密生成,前端拿到的值是密文的某种编码。这种时候统计特征反映的是加密算法和编码方式,不是随机源质量,测出来的数字说明不了实际问题。
另外,如果目标系统明确禁止批量请求,或者测试授权范围不包含压力型操作,那也不该用实时采集。这种时候要么申请扩大授权,要么改成小样本手动导入,别硬来。
7. 几个提高效率的个人习惯
7.1 建立自己的基线样本库
我会把每次评估采集到的样本和结果都存下来,按“技术栈类型 + 令牌用途”分类归档。时间长了就有了一个基线库:某某框架的默认会话令牌大概是什么水平,某某语言的常见库生成的 CSRF 令牌通常多少熵。
有了基线,判断速度会快很多。新目标测出来一个 110 比特的结果,我可以立刻对比同类系统的常见值,判断是正常波动还是确实偏低。这比每次都从零开始分析要高效得多。当然,基线只能做参照,不能替代实测,不同版本、不同配置下差异可能很大。
7.2 采集脚本和 Sequencer 配合使用
纯手工操作 Sequencer 适合单点验证,做批量评估就不够用了。我的做法是用脚本负责采集和粗筛,Sequencer 负责精确分析和出图。
脚本做的事情很简单:带着有效的会话,循环请求触发令牌的接口,把提取到的令牌一行一个写进文件。跑完之后先用自己写的熵计算脚本过一遍,快速筛出熵值明显偏低的批次,再把这些批次的样本导入 Sequencer 做详细分析。这样既省时间,又能保证重点样本得到充分分析。
脚本里我会加两个保护:一是请求间隔不低于某个阈值,避免给目标造成压力;二是遇到连续失败自动停止,防止在会话失效后继续空跑污染样本。这两条看着简单,实际能避免不少麻烦。
7.3 结果呈现要让人看得懂
最后说个容易被忽略的点:结果怎么呈现。把 Sequencer 的截图直接贴进报告,对不熟悉这个工具的人来说基本等于没信息。我通常会在截图旁边加一段说明,写清楚样本量、采集时间、令牌用途、理论熵上限、实测值、偏差比例,以及基于这些数字的判断。
举个例子,我会这样写:本次采集某类会话令牌样本 20000 个,令牌长度 32 位,实际观测字符集为 16 个十六进制字符,理论每字符熵 4.0 比特,理论有效熵 128 比特;实测每字符熵 3.94 比特,有效熵约 126 比特,与理论值偏差在正常统计波动范围内;比特级分析未发现明显的位偏斜;综合判断该类令牌的随机性水平符合常见实践要求。
这种写法别人看了能复现、能核对,比单纯放一个“Excellent”的截图有价值得多。反过来,如果结论是偏低,也要把数字摆清楚,说明低在哪里、低多少、可能的影响是什么,而不是只给一个耸人听闻的定性描述。
我在实际使用中的一个体会是,Sequencer 这个工具最大的价值不在于那个评级,而在于它逼着你去量化。以前评估会话安全,很多人就是看看长度、看看字符集,凭经验给个判断。有了具体的熵值和分布图之后,讨论就有了共同的度量基础,和开发团队沟通也顺畅很多——你说“这串字符的有效信息量只有 60 比特”,比说“我觉得这个不够随机”有说服力得多。另外提醒一句,工具版本更新后界面和默认阈值可能会有调整,具体数字以你手上的版本为准,重要的结论最好用手算或者脚本交叉验证一遍,别完全依赖界面显示。