密码哈希



如果您正在创建一个需要密码进行用户身份验证的产品,则必须实施一个系统来验证用户的登录详细信息。但是,在数据库中存储未加密的密码存在重大的安全风险。

因此,有一种方法可以保护用户的密码,那就是密码哈希。因此,在本章中,我们将定义密码哈希,讨论其重要性,并展示哈希技术如何帮助现代安全地设计我们的密码。

密码哈希基础

密码哈希使用加密方法将所有数据(例如您的密码)压缩成简短的字符和/或数字字符串。密码哈希有助于阻止攻击者在网站遭到黑客攻击时访问您的登录信息。相反,他们得到的只是您的密码创建的难以理解的加密“哈希”。

Hashing Passwords

md5() 哈希函数被广泛使用,它可以从任何输入生成一个 32 个字符的字符串。以下是一些哈希示例:

  • "secret123": 5d7845ac6ee7cfffafc5fe5f35cf666d
  • "Helloworld": a165968b0a8084a041aed89bf40d581f
  • "mypassword": 34819d7beeabb9260a5c854bc85b3e44
  • "password123": 482c811da5d5b4bc6d497ffa98491e38
  • "hashingpasswords": 6b408e41b2f7a9944367d2b535a201f8

我们可以从这些例子中学到一些简单的解释:

  • 即使对输入进行微小的更改,也会完全改变哈希函数的结果。例如,更改单个字符可以完全改变输出的外观。
  • 无论输入长度如何,哈希函数始终产生相同长度的输出。它始终是相同的大小——32 个字符。
  • 如果您使用相同的输入和哈希函数,您将始终获得相同的结果。这很重要,因为它显示了该过程的一致性和可靠性。
  • 仅知道哈希函数使得仅从输出确定原始输入(例如密码)非常困难。通常,尝试通过查看大量可能性来猜测原始输入比直接尝试找出它更快。

密码哈希的工作原理?

让我们看看密码哈希的实际过程:

Hashing Passwords table
  • 用户通过浏览网站并填写表单来创建用户名和密码。
  • 将哈希函数应用于密码,并将结果存储在数据库中。
  • 用户在登录后在网站上重新输入其密码。
  • 将之前使用的相同哈希函数应用于输入的密码。
  • 服务器将此哈希与为用户保存在数据库中的哈希进行验证。
  • 如果两个哈希完全匹配,则允许用户访问。
Hashing Passwords - Hashed Table

密码哈希的安全性

鉴于哈希的长度与密码无关,您可能会倾向于使用简短且易于记忆的密码。实际上,您应该做相反的事情。您选择的密码对于保护您的数据至关重要。

一旦网络犯罪分子从网站获取密码哈希,实际的密码破解过程就开始了。此操作是在网络犯罪分子的 PC 上离线进行的。网络犯罪分子使用哈希函数来生成与您的哈希匹配的哈希。

由于这些函数是公开的,密码黑客只需计算常用单词和组合的哈希值。然后,他们将破解的密码与这些字典进行比较。

这些字典不仅包含单词。其中还包括前缀、后缀、用数字替换字母的约定(例如,使用 1 代替 l)以及许多其他内容。这意味着弱密码很容易被破解。

确保强大的密码安全性

为了确保强大的密码安全性,您需要遵循以下一些重要提示:

  • 创建长密码,并包含大小写字母、数字和特殊字符的组合。
  • 为每个帐户使用不同的密码。
  • 不要使用易于访问的个人信息,例如您的姓名、出生日期或常用词。
  • 尽可能为您的帐户启用双因素身份验证。
  • 定期更改密码,主要是针对电子邮件和银行等敏感帐户。
  • 避免将密码存储在易于访问的地方,例如纯文本文件或便签。
  • 确保您的设备和软件已更新为最新的安全补丁,以防止攻击者利用已知的漏洞。

密码存储方法

有几种方法可以安全地存储密码:

  • 哈希 - 哈希是指使用数学方法将密码转换为固定长度的字符字符串。然后将哈希后的密码保存在数据库中。用户登录时,用户的密码将再次哈希,并与存储的哈希进行比较。常用的哈希算法包括 MD5、SHA-1 和 SHA-256。
  • 加盐哈希 − 对于每个密码,在哈希之前都会添加一个唯一的随机值,称为盐。通过使用不同的盐,可以确保两个具有相同密码的用户具有不同的哈希值。加盐哈希可以防止彩虹表攻击,攻击者在彩虹表攻击中会预先计算常用密码的哈希值。
  • 密钥派生函数 (KDF) − KDF 的目的是安全地从密码中提取加密密钥。为了减缓暴力破解攻击,它们通常使用加盐和迭代计数等特性。PBKDF2(基于密码的密钥派生函数 2)和 bcrypt 是 KDF 的两个示例。
  • 密钥伸展 − 这是重复迭代哈希过程以减慢其速度的做法。由于每次尝试都需要更多的处理能力,因此暴力破解攻击的速度会因此变慢。密钥伸展技术用于 bcrypt、scrypt 和 PBKDF2 等算法。
  • 加椒 (Peppering) − 在哈希密码之前,添加一个秘密值(椒)。此方法称为加椒。椒不会存储在数据库中,而是单独存储在哈希密码之外。因为攻击者需要哈希密码和椒才能尝试破解密码,所以这增加了另一层安全保障。

密码哈希算法

密码通常使用多种技术进行安全哈希。以下是一些最常用的算法:

  • bcrypt
  • scrypt
  • Argon2
  • PBKDF2
  • SHA-256/SHA-3

密码哈希的实现

使用 Python

现在我们将实现用于哈希密码的 Python 代码,我们将使用 Python 的 hashlib 库来生成哈希对象。代码如下:

import hashlib

def hash_password(password):
   # change the password to bytes
   password_bytes = password.encode('utf-8')

   # generate a SHA-256 hash object
   hash_object = hashlib.sha256()

   # update the hash object with the password bytes
   hash_object.update(password_bytes)

   # the hexadecimal representation of the hashed password
   hashed_password = hash_object.hexdigest()

   return hashed_password

# function execution
password = "mysecure@password"
hashed_password = hash_password(password)
print("Hashed password:", hashed_password)

输出

Hashed password: dc12e653439f07e6b0ee268b5559b45bb99be057dd7edd8756d77ef96b21aaee

使用 Java

在此实现中,我们将使用 Java 的 java.security.MessageDigest 和 java.security.NoSuchAlgorithmException 类。因此,MessageDigest 将用于生成消息摘要实例,而 NoSuchAlgorithmException 类用于在找不到此类算法时抛出异常。代码如下:

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class HashingPassword  {
   public static String hashPassword(String password) throws NoSuchAlgorithmException {
      // Create a MessageDigest instance
      MessageDigest digest = MessageDigest.getInstance("SHA-256");

      // the bytes of the password
      byte[] passwordBytes = password.getBytes();

      // update the digest with the password bytes
      digest.update(passwordBytes);

      // get the hashed bytes
      byte[] hashedBytes = digest.digest();

      // change the hashed bytes to hexadecimal
      StringBuilder hexString = new StringBuilder();
      for (byte hashedByte : hashedBytes) {
         hexString.append(String.format("%02x", hashedByte));
      }

      return hexString.toString();
   }

   public static void main(String[] args) throws NoSuchAlgorithmException {
      String password = "mysecure@password";
      String hashedPassword = hashPassword(password);
      System.out.println("Hashed password: " + hashedPassword);
   }
}

输出

Hashed password: dc12e653439f07e6b0ee268b5559b45bb99be057dd7edd8756d77ef96b21aaee
广告