面试题:密码在数据库中如何保存

简介: 面试题:密码在数据库中如何保存

面试题:密码在数据库中如何保存

简介:数据安全,特别是密码的存储非常的重要,下面文章讲解,如何将密码更加安全的存储到数据库中。

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对称加密算法对密码进行加密,并将加密后的密码和密钥进行组合存储。在解密密码时,我们提取存储的加密密码和密钥,将其与解密算法一起使用,将加密密码还原为明文密码。

相关文章
|
9月前
|
安全 druid Nacos
0 代码改造实现应用运行时数据库密码无损轮转
本文探讨了敏感数据的安全风险及降低账密泄漏风险的策略。国家颁布的《网络安全二级等保2.0标准》强调了企业数据安全的重要性。文章介绍了Nacos作为配置中心在提升数据库访问安全性方面的应用,并结合阿里云KMS、Druid连接池和Spring Cloud Alibaba社区推出的数据源动态轮转方案。该方案实现了加密配置统一托管、帐密全托管、双层权限管控等功能,将帐密切换时间从数小时优化到一秒,显著提升了安全性和效率。未来,MSE Nacos和KMS将扩展至更多组件如NoSQL、MQ等,提供一站式安全服务,助力AI时代的应用安全。
489 14
|
存储 缓存 Java
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
1814 3
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
|
SQL 缓存 监控
大厂面试高频:4 大性能优化策略(数据库、SQL、JVM等)
本文详细解析了数据库、缓存、异步处理和Web性能优化四大策略,系统性能优化必知必备,大厂面试高频。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:4 大性能优化策略(数据库、SQL、JVM等)
|
架构师 数据库
大厂面试高频:数据库乐观锁的实现原理、以及应用场景
数据库乐观锁是必知必会的技术栈,也是大厂面试高频,十分重要,本文解析数据库乐观锁。关注【mikechen的互联网架构】,10年+BAT架构经验分享。
大厂面试高频:数据库乐观锁的实现原理、以及应用场景
|
存储 Java easyexcel
招行面试:100万级别数据的Excel,如何秒级导入到数据库?
本文由40岁老架构师尼恩撰写,分享了应对招商银行Java后端面试绝命12题的经验。文章详细介绍了如何通过系统化准备,在面试中展示强大的技术实力。针对百万级数据的Excel导入难题,尼恩推荐使用阿里巴巴开源的EasyExcel框架,并结合高性能分片读取、Disruptor队列缓冲和高并发批量写入的架构方案,实现高效的数据处理。此外,文章还提供了完整的代码示例和配置说明,帮助读者快速掌握相关技能。建议读者参考《尼恩Java面试宝典PDF》进行系统化刷题,提升面试竞争力。关注公众号【技术自由圈】可获取更多技术资源和指导。
|
关系型数据库 分布式数据库 数据库
PolarDB产品使用问题之在部署PolarDB-Kubernetes时,如何设置数据库密码
PolarDB产品使用合集涵盖了从创建与管理、数据管理、性能优化与诊断、安全与合规到生态与集成、运维与支持等全方位的功能和服务,旨在帮助企业轻松构建高可用、高性能且易于管理的数据库环境,满足不同业务场景的需求。用户可以通过阿里云控制台、API、SDK等方式便捷地使用这些功能,实现数据库的高效运维与持续优化。
305 56
|
存储 关系型数据库 MySQL
【Java面试题汇总】MySQL数据库篇(2023版)
聚簇索引和非聚簇索引、索引的底层数据结构、B树和B+树、MySQL为什么不用红黑树而用B+树、数据库引擎有哪些、InnoDB的MVCC、乐观锁和悲观锁、ACID、事务隔离级别、MySQL主从同步、MySQL调优
【Java面试题汇总】MySQL数据库篇(2023版)
|
数据可视化 关系型数据库 MySQL
Mysql8 如何在 Window11系统下完成跳过密钥校验、完成数据库密码的修改?
这篇文章介绍了如何在Windows 11系统下跳过MySQL 8的密钥校验,并通过命令行修改root用户的密码。
Mysql8 如何在 Window11系统下完成跳过密钥校验、完成数据库密码的修改?
|
安全 算法 Java
数据库信息/密码加盐加密 —— Java代码手写+集成两种方式,手把手教学!保证能用!
本文提供了在数据库中对密码等敏感信息进行加盐加密的详细教程,包括手写MD5加密算法和使用Spring Security的BCryptPasswordEncoder进行加密,并强调了使用BCryptPasswordEncoder时需要注意的Spring Security配置问题。
1309 0
数据库信息/密码加盐加密 —— Java代码手写+集成两种方式,手把手教学!保证能用!
|
缓存 NoSQL Redis
一天五道Java面试题----第九天(简述MySQL中索引类型对数据库的性能的影响--------->缓存雪崩、缓存穿透、缓存击穿)
这篇文章是关于Java面试中可能会遇到的五个问题,包括MySQL索引类型及其对数据库性能的影响、Redis的RDB和AOF持久化机制、Redis的过期键删除策略、Redis的单线程模型为何高效,以及缓存雪崩、缓存穿透和缓存击穿的概念及其解决方案。