题目与场景
供应方会对时间戳和原始请求体签名。请求可能延迟、重复、格式错误或在 JSON 解析时改变。实现必须防篡改、防重放且不泄漏比较时序。
面试官在考察什么
- 保留精确字节并安全解析结构化签名头。
- 按指定算法计算 HMAC 并使用恒定时间比较。
- 执行时间戳容差并保持清晰的失败行为。
作答前的澄清问题
- 供应方规定的签名字符串、摘要算法、编码和头格式是什么?
- JSON 解析前能否获得原始请求字节?
- 需要多大的时钟偏差容忍和重放标识?
- 格式错误是否统一返回拒绝,避免暴露具体失败检查?
30 秒回答框架
我会读取原始字节,安全解析时间戳与签名,拒绝超出窗口的时间,再按供应方定义的规范字符串计算 HMAC。把签名解码成字节后使用恒定时间原语比较,最后在入队前去重事件 ID。错误对外统一拒绝,内部指标区分失败类别。
分步深挖
1. 保留原始请求体
不要把解析后的 JSON 重新序列化来验签。空白、键顺序和 Unicode 转义都会改变字节。请求体只读取一次,先限大小,再把同一字节传给验签和后续解析。
2. 解析并校验签名头
拆出时间戳和带版本的签名,拒绝重复字段或无效编码,并限制时间戳长度。转换为整数后,先拒绝超出配置容差的值,再进行昂贵计算。
3. 计算并比较
构造精确签名消息,按配置摘要算法计算 HMAC,解码外部签名,并用恒定时间函数比较等长字节数组。攻击者可测量响应时,不要用普通字符串相等比较十六进制值。
4. 防止重放
验签通过后要求稳定事件 ID,以覆盖时间窗口的保留期原子记录它。合法重复请求可以返回成功,但不能重复业务副作用。
5. 测试边界
覆盖修改字节、错误密钥、错误算法、格式错误头、过期与未来时间戳、重复签名、空请求体、超大请求体和重复事件 ID。日志不能包含密钥与完整负载。
高质量示范回答
“我会保留原始请求体,解析并限制时间戳,拒绝超出重放窗口的值,再构造供应方规定的精确签名字符串。使用指定摘要算法计算 HMAC,把签名解码为字节后恒定时间比较。验签后在入队前原子去重事件 ID。对外统一拒绝格式错误,内部计数区分解析、时间、MAC 与重放失败。”
常见失误
- 验证解析后的 JSON → 序列化可能改变签名字节 → 验证原始请求体。
- 使用普通字符串相等 → 时序可能泄漏部分匹配 → 使用恒定时间字节比较。
- 跳过时间戳检查 → 合法签名可以被重放 → 执行有界窗口与事件去重。
- 记录请求头和负载 → 密钥或个人数据可能泄漏 → 只记录安全 ID 和失败类别。
追问与回答
为什么要先验签再解析?
先解析可能规范化字节,也可能消耗只能读取一次的请求流。验签必须覆盖供应方签名的原始内容,接受后再解析。
轮换期间可以接受两个签名吗?
如果供应方规定重叠期,可以在有界窗口内尝试当前与退役版本,记录成功版本并让旧密钥过期。
只校验时间戳够防重放吗?
不够。窗口内仍可反复重放合法请求。应原子保存稳定事件 ID 或摘要,并让业务操作具备幂等性。