今天学习 FastAPI 时,细致了解了一下时序攻击(Timing Attack)。核心问题很简单:用 == 比较字符串时,Python 会在第一个不匹配字符处提前返回,攻击者可以通过响应时间的微小差异逐字猜出用户名和密码。
时序攻击是怎么发生的
假设攻击者试图猜出用户名与密码,发送 johndoe / love123:
1 | if "johndoe" == "stanleyjobson" and "love123" == "swordfish": |
Python 比较到第一个字母 j 与 s 不同时就停止,应用立刻返回「错误的用户或密码」。
接下来攻击者尝试 stanleyjobsox:
1 | if "stanleyjobsox" == "stanleyjobson" and "love123" == "swordfish": |
这次需要对比到 stanleyjobso 才能判定不匹配,多花费几微秒才返回错误响应。
反应时间对攻击者的帮助
服务器多花了几微秒才返回错误,攻击者就知道开头猜对了一部分字符。然后放弃 johndoe,继续用 stanleyjobsox 这类前缀去尝试。
专业攻击
攻击者不需要手动操作,可以编写每秒执行成千上万次测试的程序,每次找到更多正确字符。利用时间差,几分钟到几小时内就可能猜出正确的用户名和密码。
使用 secrets.compare_digest() 修补
secrets.compare_digest() 会用恒定的时间比较字符串,无论差异出现在哪个位置:
1 | import secrets |
在代码中使用 secrets.compare_digest(),就可以有效防御这类时序攻击。