时序攻击(Timing Attack)是一种侧信道攻击,攻击者通过分析系统对不同输入(如密码、密钥)的响应时间来推断敏感信息,为了有效缓解时序攻击,可以采用以下策略:

- 恒定时间比较:确保所有输入的比较操作(如密码验证、HMAC校验)执行时间与输入内容无关,避免使用
strcmp、memcmp等早期退出函数,改用恒定时间比较(如哈希比较或专用库函数)。 - 延迟添加与噪声:在关键操作后添加随机延迟或固定延迟(如
sleep(随机值)),使攻击者难以准确测量执行时间,但需注意,此方法不能完全消除时序泄漏,仅增加攻击难度。 - 数据无关的处理路径:避免条件分支(如
if-else)或依赖于输入数据的循环次数,使用位运算、查表或算术运算替代分支逻辑,在密码验证中,即使密码不匹配,也继续完成剩余计算。 - 内存访问模式统一:确保内存访问模式不依赖于秘密数据,使用固定大小的缓冲区、预加载数据或使用恒定时间的内存访问(如
memcpy一定长度的数据,而非仅复制实际内容)。 - 硬件与系统级防护:禁用CPU的指令级别时序优化(如超线程、Turbo Boost),或使用支持恒定时间指令集的硬件(如ARM的
SVE指令),操作系统层面,可配置内核调度或使用preempt_rt减少时间抖动。 - 使用安全库函数:调用已实现时序安全的标准库,如OpenSSL的
CRYPTO_memcmp、libsodium的sodium_memcmp、Golang的subtle.ConstantTimeCompare等。 - 屏蔽网络延迟影响:如果攻击基于远程时序,可加入网络延迟干扰(如通过代理或VPN引入随机延迟),但此方法效果有限,因本地网络环境易被控制。
示例(伪代码/常量时间比较):
int constant_time_compare(const char *a, const char *b, size_t len) {
int diff = 0;
for (size_t i = 0; i < len; ++i) {
diff |= (a[i] ^ b[i]);
}
return diff == 0; // 注意返回值不可泄漏循环次数
}
注意事项:
- 陷阱:编译器优化可能破坏恒定时间逻辑(如循环展开、分支预测),需用硬件屏障(
asm volatile("" ::: "memory"))或编译器固有指令(如__builtin_expect)确保生成可预测的机器码。 - 测试:使用工具如
dudect、FLL或Mastik检测时序泄漏,进行重复统计测试(例如10000次测量确认时间无显著差异)。 - 适用场景:加密、认证(如密码验证、令牌校验)、密钥衍生的核心函数需严格防护;非敏感操作(如用户登录次数统计)可放宽要求。
通过组合上述方法(尤其是恒定时间比较 + 延迟噪声),可显著提高攻击成本,且结合其他侧信道防护(如功率分析、电磁泄露)形成纵深防御。