自学内容网 自学内容网

【java】签名验签防篡改研究测试

上一篇文章写了接口安全通过一次性校验码和 时间戳可以防接口重放攻击、本篇将通过 signatrue签名模式进行研究性,知其所以然

说明本次实验是验证签名合法性该前端使用不安全加密,存在安全风险密钥在jsp中暴露

1、实现原理

2、前端

将 username 和 password 以及一个 秘密密钥 拼接在一起。例如:username + password + secretKey
使用 SHA-256 算法进行加密:通过 CryptoJS.SHA256 对拼接后的字符串进行加密。
生成 Base64 编码的签名:toString(CryptoJS.enc.Base64) 将加密结果转换成 Base64 编码便于传输

sign前端代码

<%@ page contentType="text/html; charset=UTF-8" language="java" %>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>sginnatrue</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.js"></script>
</head>
<body>
<h2>签名验签sign测试</h2>
<form id="loginForm" method="POST" action="/sign">
    <label for="username">用户名:</label>
    <input type="text" id="username" name="username" required/><br/>

    <label for="password">密码:</label>
    <input type="password" id="password" name="password" required/><br/>

    <!-- 加入时间戳和Nonce -->
    <input type="hidden" name="timestamp" value="${timestamp}"/>
    <input type="hidden" name="nonce" value="${nonce}"/>
    <input type="hidden" name="signature" id="signature"/>

    <button type="submit">登录</button>
</form>
<br/>
 <p type="hidden" style="color:red">时间戳: ${timestamp}</p >
 <p type="hidden" style="color:red">一次性校验码: ${nonce}</p >


<script>
    // 生成签名的函数
    function generateSignature(username, password) {
        const secretKey = "yourSecretKey"; // 后端验证签名时用的密钥(应该由后端安全管理)
        const data = username + password + secretKey; // 拼接数据
        const signature = CryptoJS.SHA256(data).toString(CryptoJS.enc.Base64); // 生成签名(Base64 编码)
        return signature;
    }

    // 在表单提交前生成签名并填入表单
    document.getElementById('loginForm').onsubmit = function (event) {
        const username = document.getElementById('username').value;
        const password = document.getElementById('password').value;
        const signature = generateSignature(username, password);

        // 填充隐藏的签名字段
        document.getElementById('signature').value = signature;
    }
</script>
</body>
<br/>
<p style="color:red">${error}</p >
<p style="color:red">${success}</p >
</html>

3、后端

后端使用相同的拼接规则和密钥,重新生成签名并与前端发送的签名进行比对。如果一致,则验证通过

 @GetMapping("/sign")
    public String showNonce1(Model model) {
        long timestamp = System.currentTimeMillis();
        String nonce = UUID.randomUUID().toString();

        model.addAttribute("timestamp", timestamp);
        model.addAttribute("nonce", nonce);

        return "sign";
    }

    @PostMapping("/sign")
    public String handleLogin(@RequestParam String username,
                              @RequestParam String password,
                              @RequestParam String signature,
                              @RequestParam long timestamp,
                              @RequestParam String nonce,
                              Model model) throws NoSuchAlgorithmException {
        System.out.println("前端的签名:" + signature);
        String data = username + password + SECRET_KEY; // 数据拼接顺序与前端一致
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        byte[] hashBytes = digest.digest(data.getBytes());
        //System.out.println(hashBytes);
        String hou = Base64.getEncoder().encodeToString(hashBytes);
        if(hou.equals(signature)){
            System.out.println("验签成功");
            model.addAttribute("success", "  欢迎用户   "+username+"  验签成功!");
            return "home";
        }else{
            System.out.println("验签失败");
            model.addAttribute("error", "  "+ username+" 验签失败!");
        }
        return "fail";
    }

验证测试

合法操作未篡改参数正常触发请求,响应正常

篡改username重放请求 提示username参数已被篡改,后端生成的签名与前端不一致则跳出失败界面


原文地址:https://blog.csdn.net/weixin_43372364/article/details/145307576

免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!