今天学习FastAPI时,细致了解了一下时差攻击。
时差攻击
什么是时差攻击?
假设攻击者试图猜出用户名与密码。
他们发送用户名为 johndoe,密码为 love123 的请求。
然后,Python 代码执行如下操作:
1 | if "johndoe" == "stanleyjobson" and "love123" == "swordfish": |
但就在 Python 比较完 johndoe 的第一个字母 j 与 stanleyjobson 的 s 时,Python 就已经知道这两个字符串不相同了,它会这么想,没必要浪费更多时间执行剩余字母的对比计算了。应用立刻就会返回错误的用户或密码。
但接下来,攻击者继续尝试 stanleyjobsox 和 密码 love123。
应用代码会执行类似下面的操作:
1 | if "stanleyjobsox" == "stanleyjobson" and "love123" == "swordfish": |
此时,Python 要对比 stanleyjobsox 与 stanleyjobson 中的 stanleyjobso,才能知道这两个字符串不一样。因此会多花费几微秒来返回错误的用户或密码。
反应时间对攻击者的帮助
通过服务器花费了更多微秒才发送错误的用户或密码响应,攻击者会知道猜对了一些内容,起码开头字母是正确的。
然后,他们就可以放弃 johndoe,再用类似 stanleyjobsox 的内容进行尝试。
专业攻击
当然,攻击者不用手动操作,而是编写每秒能执行成千上万次测试的攻击程序,每次都会找到更多正确字符。
但是,攻击者利用时间差,就能在几分钟或几小时内,以这种方式猜出正确的用户名和密码。
使用 secrets.compare_digest() 修补
在此,代码中使用了 secrets.compare_digest()。
简单的说,它使用相同的时间对比 stanleyjobsox 和 stanleyjobson,还有 johndoe 和 stanleyjobson。对比密码时也一样。
在代码中使用 secrets.compare_digest() ,就可以安全地防御全面攻击了。
1 | current_username_bytes = credentials.username.encode("utf8") |