Python 程序使用散列(又称哈希)将输入数据转换成一个固定大小的值。该值唯一地表示数据,散列技术使各种形式的数据的安全传输和存储变得容易。
散列可以保护数据免受未经授权的访问和篡改。它是数据完整性和安全用例中的重要组成部分。
本文探讨了关于 Python 散列所需了解的一切。它深入探讨了散列的用途,并重点介绍了各种散列算法,这些算法可使您的代码更加高效、安全和可靠。
什么是 Python 中的散列?
散列将输入数据(如字符串、文件或对象)转换为固定大小的字节串。哈希值或摘要以唯一且可重现的方式表示输入。
散列在检测数据操作和增强安全性方面发挥着重要作用。它可以为文件、信息或其他数据计算哈希值。应用程序可以安全地存储哈希值,以便日后验证数据是否被篡改。
哈希值在安全方面最常见的用途之一就是密码存储。散列是在数据库中存储纯文本密码的一种可行替代方法。当用户输入密码时,系统会先对密码进行散列处理,然后再将其存储到数据库中。如果黑客访问数据库,他们会发现密码很难被窃取。
Python 哈希函数使这一切成为可能。这些数学函数可以让应用程序将数据处理成散列值。
如何制作有效的散列函数
散列函数应符合以下标准,才能有效且安全:
- 确定性 – 给定相同的输入,函数应始终返回相同的输出。
- 高效 – 在计算任何给定输入的散列值时,它应具有较高的计算效率。
- 抗碰撞 – 函数应尽量减少两个输入产生相同哈希值的几率。
- 均匀性 – 函数的输出应均匀分布在可能的哈希值范围内。
- 不可逆转 – 计算机不可能根据哈希值计算出函数的输入值。
- 不可预测 – 在给定一组输入的情况下,预测函数的输出应具有挑战性。
- 对输入变化敏感 – 函数应对输入中的微小差异非常敏感。微小的变化应导致结果哈希值的巨大差异。
散列使用案例
一旦掌握了具备所有这些特性的散列函数,就可以将其应用于各种用例。散列函数可以很好地用于:
- 密码存储 – 散列是现代系统中存储用户密码的最佳方法之一。Python 结合各种模块对密码进行散列并确保其安全,然后再将其存储到数据库中。
- 缓存 – 散列可以存储函数的输出,以便在以后调用时节省时间。
- 数据检索 – Python 使用带有内置字典数据结构的散列表,可按键快速检索值。
- 数字签名 – 散列可以验证具有数字签名的信息的真实性。
- 文件完整性检查 – 散列可以检查文件在传输和下载过程中的完整性。
Python 内置散列函数
Python 内置的散列函数 hash()
返回一个代表输入对象的整数值。然后,代码使用得到的散列值来确定对象在散列表中的位置。哈希表是一种实现了字典和集合的数据结构。
下面的代码演示了 hash()
函数如何工作:
my_string = "hello world" # Calculate the hash value of the string hash_value = hash(my_string) # Print the string and its hash value print("String: ", my_string) print("Hash value: ", hash_value)
如果我们将代码保存在名为 hash.py 的文件中,就可以像这样执行它(并查看输出):
% python3 hash.py String: hello world Hash value: 2213812294562653681
让我们再运行一次:
% python3 hash.py String: hello world Hash value: -631897764808734609
由于最近发布的 Python(3.3 及更高版本)默认为该函数应用随机哈希种子,因此第二次调用时的哈希值是不同的。每次调用 Python 时,种子都会改变。在单个实例中,结果将是相同的。
例如,让我们把这段代码放到 hash.py 文件中:
my_string = "hello world" # Calculate 2 hash values of the string hash_value1 = hash(my_string) hash_value2 = hash(my_string) # Print the string and its hash values print("String: ", my_string) print("Hash value 1: ", hash_value1) print("Hash value 2: ", hash_value2)
执行时,我们会看到这样的画面:
String: hello world Hash value 1: -7779434013116951864 Hash value 2: -7779434013116951864
散列的局限性
尽管 Python 的哈希函数在各种用例中都很有前途,但它的局限性使其不适合用于安全目的。下面就来看看它的局限性:
- 碰撞攻击 – 当两个不同的输入产生相同的散列值时,就会发生碰撞。攻击者可以使用相同的输入方法绕过依赖哈希值进行身份验证或数据完整性检查的安全措施。
- 有限的输入大小 – 由于散列函数会产生固定大小的输出,而与输入的大小无关,因此大于散列函数输出的输入会导致碰撞。
- 可预测性 – 哈希函数应具有确定性,每次提供相同的输入都会产生相同的输出。攻击者可能会利用这一弱点,预先编译许多输入的哈希值,然后将它们与目标值哈希值进行比较,找出匹配的结果。这个过程被称为彩虹表攻击。
为防止攻击并确保数据安全,请使用专为抵御此类漏洞而设计的安全散列算法。
在 Python 中使用 hashlib 实现安全散列
与其使用内置的 Python hash()
,不如使用 hashlib 来获得更安全的散列。该 Python 模块提供了多种安全散列数据的散列算法。这些算法包括 MD5、SHA-1 和更安全的 SHA-2 系列,包括 SHA-256、SHA-384、SHA-512 等。
MD5
广泛使用的加密算法 MD5 能生成 128 位的散列值。使用下面的代码,使用 hashlib 的 md5
构造函数生成 MD5 哈希值:
import hashlib text = "Hello World" hash_object = hashlib.md5(text.encode()) print(hash_object.hexdigest())
上述结果(在我们的 hash.py 文件中)在不同的调用中将保持一致:
b10a8db164e0754105b7a99be72e3fe5
注:上述代码中的 hexdigest()
方法以十六进制格式返回哈希值,可用于任何非二进制表达(如电子邮件)。
SHA-1
SHA-1 散列函数通过生成一个 160 位的散列值来确保数据安全。使用下面的代码和 sha1
构造函数来获取 hashlib 模块的 SHA-1 哈希值:
import hashlib text = "Hello World" hash_object = hashlib.sha1(text.encode()) print(hash_object.hexdigest())
上述结果的输出:
0a4d55a8d778e5022fab701977c5d840bbc486d0
SHA-256
SHA-2 系列有多种散列选项。hashlib SHA-256 构造函数可生成该系列中更安全的 256 位散列值。
程序员经常将 SHA-256 用于加密,如数字签名或消息验证码。下面的代码演示了如何生成 SHA-256 哈希值:
import hashlib text = "Hello World" hash_object = hashlib.sha256(text.encode()) print(hash_object.hexdigest())
上述结果的输出:
a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e
SHA-384
SHA-384 是一个 384 位的散列值。程序员经常在需要提高数据安全性的应用程序中使用 SHA-384 函数。
根据前面的示例,你大概可以猜到这是一条生成 SHA-384 散列值的语句:
hash_object = hashlib.sha384(text.encode())
SHA-512
SHA-512 是 SHA-2 家族中最安全的成员。它能生成 512 位的散列值。程序员将其用于高吞吐量应用,如检查数据完整性。下面的代码展示了如何使用 Python 中的 hashlib 模块生成 SHA-512 哈希值:
hash_object = hashlib.sha512(text.encode())
如何选择散列算法
由于这些算法各不相同,因此应根据使用情况及其安全要求选择散列算法。下面是一些应遵循的步骤:
- 了解用例 – 用例决定了使用哪种算法。例如,在存储密码等敏感数据时,散列算法应能防止暴力攻击。
- 考虑你的安全要求 – 用例的安全要求取决于你打算存储的数据类型,它们决定了要选择什么样的算法。例如,稳健的散列算法最适合存储高度敏感的信息。
- 研究可用的散列算法 – 探索每种散列类型,了解其优缺点。这些信息可以帮助你选择最适合你的使用案例的选项。
- 评估所选散列算法 – 一旦选择了散列算法,就要评估它是否符合安全要求。这一过程可能包括针对已知攻击或漏洞进行测试。
- 实施和测试散列算法 – 最后,彻底实施和测试该算法,以确保其正确、安全地运行。
如何使用散列存储密码
散列技术在存储密码方面具有出色的潜力,而密码是网络安全的一个重要组成部分。
理想情况下,应用程序会将密码散列并存储在安全的数据库中,以防止未经授权的访问和数据泄露。不过,仅靠散列可能不足以保护信息。散列密码仍然容易受到暴力和字典攻击。黑客通常使用这些方法来猜测密码,并在未经授权的情况下访问账户。
使用散列存储密码的更安全方法是加盐技术。在对密码进行散列运算之前,加盐技术会在每个密码中添加唯一的随机字符串或字符。盐值对每个密码都是唯一的,应用程序会将其与散列密码一起存储在数据库中。
每次用户登录时,应用程序都会从数据库中检索盐值,将其添加到输入的密码中,然后对组合后的盐值和密码进行散列。
如果攻击者获得了数据库的访问权限,他们就必须为每个密码和每个可能的盐值计算散列值。加盐会使这些攻击变得更加复杂,因此是阻止字典攻击的有效技术。
Python 的 secrets 模块让加盐变得简单。该模块可生成随机盐,安全地存储密码并管理令牌和加密密钥。
下面的代码使用 hashlib 库和 secrets 模块来进一步保护用户密码:
import hashlib import secrets # Generate a random salt using the secrets module salt = secrets.token_hex(16) # Get the user's password from input password = input("Enter your password: ") # Hash the password using the salt and the SHA-256 algorithm hash_object = hashlib.sha256((password + salt).encode()) # Get the hexadecimal representation of the hash hash_hex = hash_object.hexdigest() # Store the salt and hash hex in your database
如何使用散列进行数据完整性检查
散列还有助于检查数据的完整性,保护传输的数据不被修改和篡改。这种四步技术使用加密哈希函数为文件提供唯一的哈希值。
首先,选择适当的散列函数,用它为输入数据生成散列值。存储哈希值,然后在需要时使用它进行比较。无论何时需要验证数据的完整性,应用程序都会使用相同的哈希函数生成当前数据的哈希值。然后,应用程序将新的哈希值与存储的值进行比较,以确保它们完全相同。如果相同,则数据未损坏。
散列值是唯一的,即使输入数据发生微小的变化,也会引发明显不同的散列值。这样就很容易检测到对传输数据的任何未经授权的更改或修改。
下面的步骤演示了使用哈希函数进行数据完整性检查。
步骤 1:导入 hashlib 模块
import hashlib
步骤 2:使用哈希算法
def generate_hash(file_path): # Open the file in binary mode with open(file_path, "rb") as f: # Read the contents of the file contents = f.read() # Generate the SHA-256 hash of the contents hash_object = hashlib.sha256(contents) # Return the hexadecimal representation of the hash return hash_object.hexdigest()
步骤 3:调用函数并输入文件路径
file_path = "path/to/my/file.txt" hash_value = generate_hash(file_path) print(hash_value)
步骤 4:生成原始文件和已传输或修改文件的哈希值
# Generate the hash of the original file original_file_path = "path/to/my/file.txt" original_file_hash = generate_hash(original_file_path) # Transmit or modify the file (for example, by copying it to a different location) transmitted_file_path = "path/to/transmitted/file.txt" # Generate the hash of the transmitted file transmitted_file_hash = generate_hash(transmitted_file_path)
步骤 5:比较两个哈希值
if original_file_hash == transmitted_file_hash: print("The file has not been tampered with") else: print("The file has been tampered with")
小结
散列对于数据完整性和密码安全非常重要。使用安全的散列技术(如使用 hashlib 模块和加盐)可以最大限度地利用散列函数。
这些技术有助于防止彩虹攻击、碰撞攻击和其他影响散列的安全漏洞。程序员经常将这些技术与 Python 中的散列函数一起使用,以确保文件的数据完整性和密码的安全存储。
评论留言