面试题:密码在数据库中如何保存
简介:数据安全,特别是密码的存储非常的重要,下面文章讲解,如何将密码更加安全的存储到数据库中。
1. 哈希函数
哈希函数是一种将任意长度的数据映射为固定长度哈希值的算法。在密码存储中,我们通常使用哈希函数将用户密码转换为哈希值,并将哈希值存储在数据库中。这样,即使数据库被攻击者获取,他们也无法直接获取用户的明文密码。
常用的哈希函数包括SHA-256、SHA-512等。下面是一个Java代码示例,用于对密码进行哈希存储:
import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class PasswordUtils { public static String hashPassword(String password) { String hashedPassword = null; try { MessageDigest md = MessageDigest.getInstance("SHA-256"); byte[] hash = md.digest(password.getBytes(StandardCharsets.UTF_8)); hashedPassword = bytesToHex(hash); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return hashedPassword; } private static String bytesToHex(byte[] bytes) { StringBuilder result = new StringBuilder(); for (byte b : bytes) { result.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1)); } return result.toString(); } public static void main(String[] args) { String password = "password123"; String hashedPassword = hashPassword(password); System.out.println("Hashed Password: " + hashedPassword); } }
在上面的代码中,我们使用SHA-256哈希函数对密码进行哈希,并将哈希值转换为十六进制字符串进行存储。
2. 加盐哈希
为了进一步增加密码的安全性,我们可以使用加盐哈希来存储密码。加盐是在密码哈希过程中引入一个随机生成的字符串,将其与密码进行组合后再进行哈希。这样可以防止攻击者使用预先计算好的哈希表(彩虹表)进行密码破解。
下面是一个Java代码示例,用于对密码进行加盐哈希存储:
import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Base64; public class PasswordUtils { public static String hashPassword(String password) { String hashedPassword = null; try { // 生成随机盐 SecureRandom random = new SecureRandom(); byte[] salt = new byte[16]; random.nextBytes(salt); // 将盐与密码组合后进行哈希 MessageDigest md = MessageDigest.getInstance("SHA-256"); md.update(salt); byte[] hash = md.digest(password.getBytes(StandardCharsets.UTF_8)); // 将盐和哈希值进行组合存储 String saltString = Base64.getEncoder().encodeToString(salt); String hashString = Base64.getEncoder().encodeToString(hash); hashedPassword = saltString + "$" + hashString; } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return hashedPassword; } public static boolean verifyPassword(String password, String hashedPassword) { boolean isValid = false; try { // 提取盐和哈希值 String[] parts = hashedPassword.split("\\$"); String saltString = parts[0]; String hashString = parts[1]; byte[] salt = Base64.getDecoder().decode(saltString); byte[] hash = Base64.getDecoder().decode(hashString); // 将盐与密码组合后进行哈希 MessageDigest md = MessageDigest.getInstance("SHA-256"); md.update(salt); byte[] newHash = md.digest(password.getBytes(StandardCharsets.UTF_8)); // 验证哈希值是否一致 isValid = MessageDigest.isEqual(hash, newHash); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return isValid; } public static void main(String[] args) { String password = "password123"; String hashedPassword = hashPassword(password); System.out.println("Hashed Password: " + hashedPassword); boolean isValid = verifyPassword(password, hashedPassword); System.out.println("Password Valid: " + isValid); } }
在上面的代码中,我们使用SHA-256哈希函数对密码进行加盐哈希,并将盐和哈希值进行组合存储。在验证密码时,我们提取存储的盐和哈希值,将其与用户输入的密码进行相同的哈希运算,然后比较哈希值是否一致。
3. 密码加密算法
除了哈希函数,我们还可以使用密码加密算法对密码进行加密存储。加密是可逆的,即可以通过解密算法将加密后的密码还原为明文密码。常用的密码加密算法包括对称加密算法(如AES)和非对称加密算法(如RSA)。
下面是一个Java代码示例,用于对密码进行加密存储:
import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Base64; public class PasswordUtils { public static String encryptPassword(String password) { String encryptedPassword = null; try { // 生成密钥 KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); SecureRandom random = new SecureRandom(); keyGenerator.init(random); SecretKey secretKey = keyGenerator.generateKey(); // 加密密码 Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, secretKey); byte[] encryptedBytes = cipher.doFinal(password.getBytes(StandardCharsets.UTF_8)); // 将加密后的密码和密钥进行组合存储 String encryptedString = Base64.getEncoder().encodeToString(encryptedBytes); String keyString = Base64.getEncoder().encodeToString(secretKey.getEncoded()); encryptedPassword = encryptedString + "$" + keyString; } catch (Exception e) { e.printStackTrace(); } return encryptedPassword; } public static String decryptPassword(String encryptedPassword) { String decryptedPassword = null; try { // 提取加密后的密码和密钥 String[] parts = encryptedPassword.split("\\$"); String encryptedString = parts[0]; String keyString = parts[1]; byte[] encryptedBytes = Base64.getDecoder().decode(encryptedString); byte[] keyBytes = Base64.getDecoder().decode(keyString); // 解密密码 SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.DECRYPT_MODE, secretKey); byte[] decryptedBytes = cipher.doFinal(encryptedBytes); decryptedPassword = new String(decryptedBytes, StandardCharsets.UTF_8); } catch (Exception e) { e.printStackTrace(); } return decryptedPassword; } public static void main(String[] args) { String password = "password123"; String encryptedPassword = encryptPassword(password); System.out.println("Encrypted Password: " + encryptedPassword); String decryptedPassword = decryptPassword(encryptedPassword); System.out.println("Decrypted Password: " + decryptedPassword); } }
在上面的代码中,我们使用AES对称加密算法对密码进行加密,并将加密后的密码和密钥进行组合存储。在解密密码时,我们提取存储的加密密码和密钥,将其与解密算法一起使用,将加密密码还原为明文密码。