结论:时序攻击通过测量操作的耗时差异推断秘密信息。经典案例:逐字节比较 MAC/token 的代码在第一个不同字节处返回——攻击者逐字节爆破,正确前缀越长响应越慢,256 次尝试 × 长度即可恢复整个令牌,把指数级爆破降为线性。防御是使用常数时间比较(hmac.compare_digest、crypto/subtle.ConstantTimeCompare)。
展开:常数时间比较的原理:长度公开(长度本身通常不敏感)后,对所有字节做异或累加,最后判断是否为零——执行路径与数据无关:
func equal(a, b []byte) bool {
if len(a) != len(b) { return false }
var v byte
for i := range a { v |= a[i] ^ b[i] }
return v == 0 // 无提前退出,无分支依赖数据
}
注意编译器可能把"聪明"的优化加回去(识别出等价于 memcmp),所以必须用密码库的实现而非手写。更广的侧信道:1)缓存时序——AES 查表实现可被 cache-timing 攻破,现代用 AES-NI 指令或 bitslice 实现;2)分支预测——密码学代码要求"常数时间":无数据依赖的分支、无数据依赖的内存寻址;3)远端可观测性——网络时序噪声大,但统计放大(重复请求取最小值/中位数)让远程时序攻击在研究中反复被证明可行,别抱侥幸。易错点:== 比较 password hash、JWT 签名、API key 都是高危点;字符串 == 在多数语言就是逐字节提前退出。
追问方向:Spectre/Meltdown 与微架构侧信道的层级、常数时间编程在 LLVM 的验证工具(ct-verif、valgrind 的 ct 模式)。