用户密码保存加密场景

>>最全面的Java面试大纲及答案解析(建议收藏)  

保证用户账号密码的安全十分重要,本文介绍的是在时间复杂度和空间复杂度上增加破解的难度。

  • 固定盐:固定盐就是使用输定数据参与摘要计算,好处是实现简单,缺点是安全性不足,一旦“盐”被泄露会影响所有用户。

  • 随机盐:每次计算摘要计算都使用的盐,比如按照一定的规则,针对每一个用户生成一个随机盐,一个用户使用同一个盐,不同之间的用户“盐”不用,这样即使一个用户密码被破解,也不影响其他用户,另外在用户重置密码时也需要重新生成盐。

  • 循环hash,延长计算时间,增加破解难度,PBKDF2, bcrypt, scrypt 就是这类的算饭。由于 MD5,SHA系列算法都是运算比较快的算法,随着硬件的发展,单次摘要计算获得结果也变得容易被破解,可以说只是时间问题,为了应对这种问题,引入了“拉伸”概念,就是通过多次循环 hash 加密算法变慢(在RFC2898文案中推荐 推荐不小于1000次),增加攻击者的时间成本,使得暴力破解变得非常困难。

具体代码如下所示:
package com.java.hash;

import org.apache.commons.codec.binary.Base64;

import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;

public class UserPasswordHash {
    // 生成摘要长度 512 位,理论上越长的摘要越难破解。
    private static final int HASH_BIT_SIZE = 512;

    // 迭代次数,按照 在RFC2898文案中推荐 的建议,不少以100次
    private static final int ITERATIONS = 2000;

    // 盐的长度,按照 RFC2898 中的建议,盐的长度不低于64位
    private static final int SALT_BIT_SIZE = 64;

    // 创建密码摘要
    public static String genPasswordHash(String password, String salt)
            throws NoSuchAlgorithmException, InvalidKeySpecException 
{
        PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), Base64.decodeBase64(salt), ITERATIONS, HASH_BIT_SIZE);
        SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
        byte[] hash = skf.generateSecret(spec).getEncoded();

        return Base64.encodeBase64String(hash);
    }

    // 生成随机盐
    public static String genRandomSalt() {
        byte[] salt = new byte[SALT_BIT_SIZE];
        SecureRandom rand = new SecureRandom();
        rand.nextBytes(salt);
        return Base64.encodeBase64String(salt);
    }

    // 验证密码
    public static boolean verify(String password, String salt, String passHash)
            throws NoSuchAlgorithmException, InvalidKeySpecException 
{
        String hash = genPasswordHash(password, salt);
        return hash.equals(passHash);
    }

    public static void savePasswordDemo(String passwordHash, String salt) {
        //密码Hash 和 salt 同时存储
    }

    public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException {
        //原始密码
        String weakPassword = "123456";
        //生成随机盐
        String salt = genRandomSalt();
        //经过加盐后的密码摘要
        String passwordHash = genPasswordHash(weakPassword, salt);
        //同时储存密码hash和盐
        savePasswordDemo(passwordHash, salt);
        //验证密码
        boolean resualt = verify(weakPassword, salt, passwordHash);
        System.out.println(resualt);
    }
}
输出结果如下所示:

用户密码保存加密场景

END


用户密码保存加密场景

长按二维码识别关注


喜欢就点击“好看”吧!


原文始发于微信公众号(一盏红茶):用户密码保存加密场景