【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)!