java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringBoot 随机盐值+双重SHA256加密

SpringBoot中随机盐值+双重SHA256加密实战

作者:MoCrane

本文主要介绍了SpringBoot中随机盐值+双重SHA256加密实战,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

1.SHA-256和Salt

1.1.什么是SHA-256

SHA-256是一种信息摘要算法,也是一种密码散列函数。对于任意长度的消息,SHA256都会产生一个256bit长的散列值(哈希值),用于确保信息传输完整一致,称作消息摘要。这个摘要相当于是个长度为32个字节的数组,通常用一个长度为64的十六进制字符串来表示。

SHA-256的具备以下几个关键特点:

除了SHA-256之外,还有一个密码散列函数MD5,过去也常被用于密码加密,但MD5在安全性上低于SHA-256,现在已经很少用于密码加密了,本文不做考虑。

SHA-256 和 MD5 的比较:

特性SHA-256MD5
输出长度256 位(64 个十六进制字符)128 位(32 个十六进制字符)
安全性
计算速度较慢
抗碰撞能力
应用场景数据完整性校验、数字签名、密码存储、区块链曾用于文件校验、密码存储
推荐使用

1.2.什么是随机盐值

盐值(salt) 是一种在密码学和安全计算中常用的随机数据,用于增强密码散列的安全性。

随机盐值(random salt)是一种用于增强密码散列安全性的技术。它是一个随机生成的数据块,在将密码输入散列函数之前,将盐值与密码组合。通过引入随机盐值,可以有效地防止彩虹表攻击和相同密码散列值重复的问题。

盐值的作用:

1.3.如何进行加密操作

本文采用的加密方式是在前端采用md加密防止明文传输,后端对密码二次加密后再进行随机盐值的混入。

2.前端实现

引入md5.min.js

<!DOCTYPE html>
<html lang="en"
      xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
    <!-- jquery -->
    <script type="text/javascript" th:src="@{/js/jquery.min.js}"></script>
    <!-- bootstrap -->
    <link rel="stylesheet" type="text/css" th:href="@{/bootstrap/css/bootstrap.min.css}" rel="external nofollow" />
    <script type="text/javascript" th:src="@{/bootstrap/js/bootstrap.min.js}"></script>
    <!-- jquery-validator -->
    <script type="text/javascript" th:src="@{/jquery-validation/jquery.validate.min.js}"></script>
    <script type="text/javascript" th:src="@{/jquery-validation/localization/messages_zh.min.js}"></script>
    <!-- md5.js -->
    <script type="text/javascript" th:src="@{/js/md5.min.js}"></script>
    <!-- common.js -->
    <script type="text/javascript" th:src="@{/js/common.js}"></script>
</head>
<body>
<form name="loginForm" id="loginForm" method="post" style="width:50%; margin:0 auto">

    <h2 style="text-align:center; margin-bottom: 20px">用户登录</h2>

    <div class="form-group">
        <div class="row">
            <label class="form-label col-md-4">请输入手机号码</label>
            <div class="col-md-5">
                <input id="mobile" minlength="11" maxlength="11" name="mobile" class="form-control" type="text" placeholder="手机号码" required="true"/>
            </div>
        </div>
    </div>

    <div class="form-group">
        <div class="row">
            <label class="form-label col-md-4">请输入密码</label>
            <div class="col-md-5">
                <input id="password" name="password" class="form-control" type="password" placeholder="密码" required="true" />
            </div>
        </div>
    </div>

    <div class="row">
        <div class="col-md-5">
            <button class="btn btn-primary btn-block" type="reset" onclick="reset()">重置</button>
        </div>
        <div class="col-md-5">
            <button class="btn btn-primary btn-block" type="submit" onclick="login()">登录</button>
        </div>
    </div>
</form>
</body>
<script>
    function login() {
        $("#loginForm").validate({
            submitHandler: function (form) {
                doLogin();
            }
        });
    }

    function doLogin() {
        var inputPass = $("#password").val();
        var salt = "1a2b3c4d";
        var str = "" + salt.charAt(0) + salt.charAt(2) + inputPass + salt.charAt(5) + salt.charAt(4);
        var password = md5(str);

        $.ajax({
            url: "/login/doLogin",
            type: "POST",
            data: {
                mobile: $("#mobile").val(),
                password: password
            },
            success: function (data) {
                layer.closeAll();
                if (data.code == 200) {
                    layer.msg("成功");
                    console.log(data);
                    document.cookie = "userTicket=" + data.object;
                    window.location.href = "/goods/toList";
                } else {
                    layer.msg(data.message);
                }
            },
            error: function () {
                layer.closeAll();
            }
        });
    }
</script>
</html>

3.后端实现

3.1.导入Maven依赖

 <dependency>
     <groupId>commons-codec</groupId>
     <artifactId>commons-codec</artifactId>
     <version>1.15</version>
</dependency>

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.12.0</version>
</dependency>

3.2.密码加密

3.2.1.密码加盐

首先使用Apache的RandomStringUtils工具类,生成16位的盐值。然后将盐拼接到明文后面,进行SHA256加密。

这个加密后的SHA256是个固定64长度的字符串。

// 生成一个16位的随机数,也就是盐
String salt = RandomStringUtils.randomAlphanumeric(16);

// 将盐拼接到明文后,并生成新的sha256码
String sha256Hex = DigestUtils.sha256Hex(password + salt);

3.2.2.随机盐值混合

加盐后的SHA256码长度为80位,这里我们采用的盐值混合规则:将SHA-256散列值的每四个字符中间插入一个盐值字符,依次交替排列。

// 将盐混到新生成的SHA-256码中,之所以这样做是为了后期解密,校验密码
StringBuilder sb = new StringBuilder(80); // SHA-256是64个字符,加16个字符的盐,总共80个字符
for (int i = 0; i < 16; i++) {
    sb.append(sha256Hex.charAt(i * 4));
    sb.append(salt.charAt(i));
    sb.append(sha256Hex.charAt(i * 4 + 1));
    sb.append(sha256Hex.charAt(i * 4 + 2));
    sb.append(sha256Hex.charAt(i * 4 + 3));
}
return sb.toString();

这样就完成了加密的操作:密码加盐 + 盐值混合

3.3.密码解密

3.3.1.提取盐值和加盐密码

按照加密时采用的规则:将SHA-256散列值的每四个字符中间插入一个盐值字符,依次交替排列。

我们可以将盐值和加盐后的SHA-256码

// 提取盐值和加盐后的SHA-256码
StringBuilder sb1 = new StringBuilder(64);
StringBuilder sb2 = new StringBuilder(16);

for (int i = 0; i < 16; i++) {
    sb1.append(encrypted.charAt(i * 5));
    sb1.append(encrypted.charAt(i * 5 + 2));
    sb1.append(encrypted.charAt(i * 5 + 3));
    sb1.append(encrypted.charAt(i * 5 + 4));
    sb2.append(encrypted.charAt(i * 5 + 1));
}

String sha256Hex = sb1.toString();
String salt = sb2.toString();

3.3.2.比较密码

最后,将取出的盐值与原始密码再次加盐,再次得到加盐密码,与sha256Hex比较即可判断密码是否相同。

// 比较二者是否相同
return  DigestUtils.sha256Hex(password + salt).equals(sha256Hex);

3.4.完整工具类

public class SHA256Util {

    /**
     * 加密
     * 生成盐和加盐后的SHA-256码,并将盐混入到SHA-256码中,对SHA-256密码进行加强
     **/
    public static String encryptPassword(String password) {
        // 生成一个16位的随机数,也就是盐
        String salt = RandomStringUtils.randomAlphanumeric(16);

        // 将盐拼接到明文后,并生成新的sha256码
        String sha256Hex = DigestUtils.sha256Hex(password + salt);

        // 将盐混到新生成的SHA-256码中,之所以这样做是为了后期解密,校验密码
        StringBuilder sb = new StringBuilder(80); // SHA-256是64个字符,加16个字符的盐,总共80个字符
        for (int i = 0; i < 16; i++) {
            sb.append(sha256Hex.charAt(i * 4));
            sb.append(salt.charAt(i));
            sb.append(sha256Hex.charAt(i * 4 + 1));
            sb.append(sha256Hex.charAt(i * 4 + 2));
            sb.append(sha256Hex.charAt(i * 4 + 3));
        }
        return sb.toString();
    }

    /**
     * 解密
     * 从混入盐的SHA-256码中提取盐值和加盐后的SHA-256码
     **/
    public static boolean verifyPassword(String password, String encrypted) {
        // 提取盐值和加盐后的SHA-256码
        StringBuilder sb1 = new StringBuilder(64);
        StringBuilder sb2 = new StringBuilder(16);

        for (int i = 0; i < 16; i++) {
            sb1.append(encrypted.charAt(i * 5));
            sb1.append(encrypted.charAt(i * 5 + 2));
            sb1.append(encrypted.charAt(i * 5 + 3));
            sb1.append(encrypted.charAt(i * 5 + 4));
            sb2.append(encrypted.charAt(i * 5 + 1));
        }

        String sha256Hex = sb1.toString();
        String salt = sb2.toString();

        // 比较二者是否相同
        return  DigestUtils.sha256Hex(password + salt).equals(sha256Hex);
    }
}

到此这篇关于SpringBoot中随机盐值+双重SHA256加密实战的文章就介绍到这了,更多相关SpringBoot 随机盐值+双重SHA256加密内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家! 

您可能感兴趣的文章:
阅读全文