springboot 和 js (vue) 实现SM3加密 防篡改

一、以下是对引入SM3进行说明

1.首先导入jar

<dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk15on</artifactId><version>1.68</version>
</dependency>

2.写一个java的SM3工具类

import java.io.UnsupportedEncodingException;
import java.security.Security;
import java.util.Arrays;import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;public class SM3 {private static final String ENCODING = "UTF-8";static {Security.addProvider(new BouncyCastleProvider());}/*** SM3加密* @param paramStr 待加密字符串* @return    返回加密后,固定长度=32的16进制字符串*/public static String encrypt(String paramStr) {//将返回的hash值转换为16进制字符串String resultHexString = "";try {//将字符串转换成byte数组byte[]  srcData = paramStr.getBytes(ENCODING);byte[] resultHash = hash(srcData);//将返回的hash值转换成16进制字符串resultHexString = ByteUtils.toHexString(resultHash);} catch (UnsupportedEncodingException e) {e.printStackTrace();}return resultHexString;}/*** 返回长度为32的byte数组* 生成对应的hash值* @param srcData* @return*/public static byte[] hash(byte[] srcData){SM3Digest digest = new SM3Digest();digest.update(srcData,0,srcData.length);byte[] hash = new byte[digest.getDigestSize()];digest.doFinal(hash, 0);return hash;}/*** 通过指定密钥进行加密* @param key 密钥* @param srcData 被加密的byte数组* @return*/public static byte[] hmac(byte[] key,byte[] srcData){KeyParameter keyParameter = new KeyParameter(key);SM3Digest digest = new SM3Digest();HMac mac = new HMac(digest);mac.init(keyParameter);mac.update(srcData,0,srcData.length);byte[] result = new byte[mac.getMacSize()];mac.doFinal(result, 0);return result;}/*** 判断数据源与加密数据是否一致,通过验证原数组和生成是hash数组是否为同一数组,验证二者是否为同一数据* @param srcStr* @param sm3HexString* @return*/public static boolean vertify(String srcStr,String sm3HexString){boolean flag = false;try {byte[] srcData = srcStr.getBytes(ENCODING);byte[] sm3Hash = ByteUtils.fromHexString(sm3HexString);byte[] newHash = hash(srcData);if(Arrays.equals(newHash, sm3Hash));flag = true;} catch (UnsupportedEncodingException e) {e.printStackTrace();}return flag;}public static void main(String[] args){//测试String str = "412345195604153562";String hex = SM3.encrypt(str);System.out.println(hex);String str1 = "1234";String hex1 = SM3.encrypt(str1);System.out.println(hex1);String str2 = "qwer12345";String hex2 = SM3.encrypt(str2);System.out.println(hex2);String strpre = "412727";String hexpre = SM3.encrypt(strpre);System.out.println(hexpre);//验证加密后的16进制字符串与加密前的字符串是否相同boolean flag = SM3.vertify(str, hex);System.out.println(flag);}
}

3.前端需要四个js

cipher-core.js
core.js
jsbn.js
jsbn2.js
sm3.js

4.1 编写JavaScript 的页面

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="chrome=1" />
<meta name="description" content="SM3摘要加密测试" />
<title>SM3摘要加密测试</title>
<!-- for pkcs5pkey -->
<script src="js/core.js"></script>
<script src="js/cipher-core.js"></script>
<script language="JavaScript" type="text/javascript" src="js/jsbn.js"></script>
<script language="JavaScript" type="text/javascript" src="js/jsbn2.js"></script>
<script language="JavaScript" type="text/javascript" src="js/sm3.js"></script>
<script language="JavaScript" type="text/javascript">function doSM3() {/*var f1 = document.form1;var msg = f1.sm3input.value;var msgData = CryptoJS.enc.Utf8.parse(msg);var md;var sm3keycur = new SM3Digest();msgData = sm3keycur.GetWords(msgData.toString());console.log(msgData);sm3keycur.BlockUpdate(msgData, 0, msgData.length);console.log(msgData);var c3 = new Array(32);sm3keycur.DoFinal(c3, 0);f1.sm3key.value = sm3keycur.GetHex(c3).toString();*/var f1 = document.form1;var msg = f1.sm3input.value;var msgData = CryptoJS.enc.Utf8.parse(msg);var sm3keycur = new SM3Digest();msgData = sm3keycur.GetWords(msgData.toString());sm3keycur.BlockUpdate(msgData, 0, msgData.length);var c3 = new Array(32);sm3keycur.DoFinal(c3, 0);//解决sm3相同参数前后台加密不一致的问题for(var i = 0,len = c3.length; i < len; i++){if(256 == c3[i]){c3[i]=0;}}var hashHex = sm3keycur.GetHex(c3).toString();f1.sm3key.value = hashHex;return hashHex;}
</script>
</head>
<body><script type="text/javascript">if (/msie/.test(navigator.userAgent.toLowerCase())) {document.write("<p><em>若IE浏览器下提示停止运行此脚本,请选择<b>否(N)</b>继续运行。</em></p>");}</script><!-- now editing --><form name="form1"><p>加密字符串: <input type="text" name="sm3input" value="" size="100" /><br /><input type="button" value="加密" onClick="doSM3();" /><br /> 加密结果: <input type="text" name="sm3key" value="" size="100" /><br /></p></form>
</body>
</html>

4.2 如果使用的是vue 需要自己改一下

import './core'
import './cipher-core'
import './jsbn'
import './jsbn2'
import './sm3'
import { SM3Digest } from './sm3'
import { CryptoJS } from './core'
export function doSM3(plaintext) {let d = CryptoJS.enc.Utf8.parse(plaintext);let msg = d;let md;const sm3keycur = new SM3Digest();msg = sm3keycur.GetWords(msg.toString());msg.forEach(element => {console.log('asd', element)});console.log('msg', msg);sm3keycur.BlockUpdate(msg, 0, msg.length);console.log('msg1', msg);const c3 = new Array(32);sm3keycur.DoFinal(c3, 0);md = sm3keycur.GetHex(c3).toString()console.log('加密后', md);
}



编写防篡改的功能

需要一个拦截器

@Overridepublic boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler) throws Exception {//这里需要判断下是主站还是子站if (isMaster == 1) {long beginTimeThreadLocal = System.currentTimeMillis();//拦截器处理代码log.info("进入防 重放攻击 和 防篡改 拦截器!");//首先判断是不是可以不验证的 地址Set<String> uriSet = new HashSet<>(ignoredUrlsProperties.getSignUrls());boolean isMatch = false;for (String uri : uriSet) {if (uri.contains("/**")) {uri = uri.split("/\\*\\*")[0];}isMatch = request.getRequestURI().contains(uri);if (isMatch) {break;}}if (isMatch) {return true;} else {// 获取时间戳String timestamp = request.getHeader("timestamp");// 获取随机字符串String nonceStr = request.getHeader("nonceStr");// 获取签名String signature = request.getHeader("signature");//如果请求头里没有,去参数获取if (StrUtil.isEmpty(timestamp)) {timestamp = request.getParameter("timestamp");}if (StrUtil.isEmpty(nonceStr)) {nonceStr = request.getParameter("nonceStr");}if (StrUtil.isEmpty(signature)) {signature = request.getParameter("signature");}if (StrUtil.isEmpty(timestamp)) {throw new Exception("invalid  timestamp:验证失败,无效的时间戳");}long receiveTime = Long.parseLong(timestamp);// 判断时间是否大于 1 分钟 (防止重放攻击)long NONCE_STR_TIMEOUT_SECONDS = 1L;if ((System.currentTimeMillis() - receiveTime) / (1000 * 60) >= NONCE_STR_TIMEOUT_SECONDS) {//addLog(beginTimeThreadLocal,request,"验证失败,数据被重放","REPLAY");throw new Exception("invalid  timestamp:验证失败,时间戳过期");}// 判断该用户的nonceStr参数是否已经在redis中(防止短时间内的重放攻击)Boolean haveNonceStr = redisTemplate.hasKey(SecurityConstant.NONCE + nonceStr);if (haveNonceStr) {addLog(beginTimeThreadLocal, request, "验证失败,会话被重放", "REPLAY");throw new Exception("invalid nonceStr:验证失败,会话被重放");}// 对请求头参数进行签名if (StrUtil.isEmpty(signature) || !Objects.equals(signature, this.signature(timestamp, nonceStr, request))) {addLog(beginTimeThreadLocal, request, "验证失败,数据被篡改", "TAMPERING");throw new Exception("invalid signature:验证失败,数据被篡改");}// 将本次用户请求的nonceStr参数存到redis中设置xx秒后自动删除redisTemplate.opsForValue().set(SecurityConstant.NONCE + nonceStr, nonceStr, NONCE_STR_TIMEOUT_SECONDS, TimeUnit.MINUTES);log.info("验证通过");return true;}}return true;}/*** 这里是后端生成的 sm3加密编码* (通过 参数+时间戳+随机数   生成的编码)* @param timestamp* @param nonceStr* @param request* @return* @throws UnsupportedEncodingException*/private String signature(String timestamp, String nonceStr, HttpServletRequest request) {Map<String, Object> params = new HashMap<>(16);Enumeration<String> enumeration = request.getParameterNames();while (enumeration.hasMoreElements()){String name = enumeration.nextElement();String value = request.getParameter(name);params.put(name, value);}//获取参数,因为有的接口是没有参数的,所以要单独处理下String param=this.sortQueryParamString(params);String qs ;if(StringUtils.isNotEmpty(param)){qs=String.format("%s&timestamp=%s&nonceStr=%s", param, timestamp, nonceStr);}else{qs=String.format("timestamp=%s&nonceStr=%s", timestamp, nonceStr);}log.info("qs:{}", qs);//从前端获取的nonce和后端的 进行对比,如果不一致则表示数据被篡改String newNonce= SM3Util.hashCodeStr(qs);log.info("newNonce:{}", newNonce);return newNonce;}/*** 按照字母顺序进行升序排序** @param params 请求参数* @return 排序后结果*/private String sortQueryParamString(Map<String, Object> params) {List<String> listKeys = Lists.newArrayList(params.keySet());Collections.sort(listKeys);StrBuilder content = StrBuilder.create();for (String param : listKeys) {//如果是全部作为参数传过来,也会接收到加密的签,所以需要过滤掉(下载和导出功能会出现)if(!param.equals("signature")){content.append(param).append("=").append(params.get(param)).append("&");}}if (content.length() > 0) {return content.subString(0, content.length() - 1);}return content.toString();}

然后需要配置这个过滤器生效


@Configuration
public class InterceptorConfiguration implements WebMvcConfigurer {@Autowiredprivate IgnoredUrlsProperties ignoredUrlsProperties;@Autowiredprivate LimitRaterInterceptor limitRaterInterceptor;@Autowiredprivate CorsInterceptor corsInterceptor;@Autowiredprivate SignAuthInterceptor replayInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 注册拦截器InterceptorRegistration ir = registry.addInterceptor(limitRaterInterceptor);// 配置拦截的路径ir.addPathPatterns("/**");// 配置不拦截的路径 避免加载css也拦截ir.excludePathPatterns(ignoredUrlsProperties.getUrls());registry.addInterceptor(getSysLogAspect()).addPathPatterns("/**").excludePathPatterns("/css/**", "/webjars/**", "/images/**", "/js/**", "/login.html");registry.addInterceptor(corsInterceptor).addPathPatterns("/**");registry.addInterceptor(replayInterceptor).addPathPatterns("/**");}

在yml文件中配置过滤的类

# 忽略url
ignored:
# 无需验证重放和篡改认证的请求signUrls:- /druid/**- /static/**- /store/**- /resources/**- /doc.html- /swagger-ui.html- /swagger-resources/**- /swagger/**- /xboot/test/**- /webjars/**

前端也需要对应的加密

这里就不写前端的了,前端传过来需要有header 头的时间戳、随机数、和校验码
那么这个校验码就是 = 所有的参数(key=value形式逐个拼接)+时间戳 +随机数

校验

前端给过来的和后端获取到的参数在进行加密,然后对比两个码是否一致即可。

springboot 和 js (vue) 实现SM3加密 防篡改相关推荐

  1. java基于sptingboot+vue的校园疫情防控系统 elementui

    我通过对新冠病毒的到来懵生了开发一套关于校园疫情防控系统,本系统采用了Java技术,将所有业务模块采用以浏览器交互的模式,选择MySQL数据库,springboot作为系统的后台框架,开发工具选择My ...

  2. java计算机毕业设计基于vue框架的疫情防控知识在线答题系统设计与实现源程序+mysql+系统+lw文档+远程调试

    java计算机毕业设计基于vue框架的疫情防控知识在线答题系统设计与实现源程序+mysql+系统+lw文档+远程调试 java计算机毕业设计基于vue框架的疫情防控知识在线答题系统设计与实现源程序+m ...

  3. springboot+jwt+shiro+vue+elementUI+axios+redis+mysql完成一个前后端分离的博客项目(笔记,帮填坑)

    根据B站up主MarkerHub视频制作的一个笔记 我的博客 B站博主链接: https://www.bilibili.com/video/BV1PQ4y1P7hZ?p=1 博主的开发文档: http ...

  4. Java项目:基于遗传算法学校排课系统(java+Springboot+Maven+mybatis+Vue+Mysql)

    源码获取:博客首页 "资源" 里下载! 一.项目简述 本系统功能包括: 排课管理,课程管理,讲师管理,班级管理,学生管理,教学资料,学习文档,在线测试,教材列表,教学设计,帮助中心 ...

  5. 将springboot项目和vue项目部署到windows 2016 server(服务器)

    将springboot项目和vue项目部署到服务器 1.服务器环境配置 1.1 服务器需要安装的环境 1.2 服务器需要配置的入站与进站规则 2.springboot项目的打包 2.1 springb ...

  6. js逆向网易云加密记录

    JS 逆向网易云加密[记录] 场景需求: 想要使网易云 音乐单曲播放次数增加,需要使用网易云接口来搞定,但是发现它的请求参数是加密了的,所以就需要来看看它是怎么加密的,从而模仿它发请求 具体操作 随便 ...

  7. vue rsa加密 php解密,【今日学习】VUE使用RSA加密技术

    原标题:[今日学习]VUE使用RSA加密技术 1 Vue端搭建 首先我们还是先安装必要的模块哈: npm install jsencrypt --save 接下来我们需要在main.js的配置文件中配 ...

  8. node.js+Vue计算机毕设项目的党务管理系统(程序+LW+部署)

    该项目含有源码.文档.程序.数据库.配套开发软件.软件安装教程.欢迎交流 项目运行 环境配置: Node.js+ Vscode + Mysql5.7 + HBuilderX+Navicat11+Vue ...

  9. vue项目中加密和解密

    Vue项目使用AES做加密 aes.js 文件内容如下: // test under node v6.11.1 const crypto = require("crypto");  ...

最新文章

  1. Vivado 随笔(2) 综合属性之use_dsp48?
  2. 春节英语祝福【中英文对照】
  3. Python3爬虫知识点总结
  4. 宝塔面板 nginx+apache共存 之 KVS服务器运行环境搭建过程记录
  5. 用qq号获取用户头像和昵称
  6. opencv 高反差保留算法
  7. matlab中怎么查看变量,Matlab 查看内存中的变量,清空屏幕等命令
  8. 解决Error基础连接已经关闭: 未能为SSL/TLS 安全通道建立信任关系
  9. GlusterFS分布式文件系统
  10. 深度技术 Windows 7 SP1 x64 极速装机版 V2013.05
  11. PHP CI框架+VUE开发环境搭建,tnpm搭建VUE环境
  12. 高等数学:第六章 定积分的应用(3)体积
  13. 解决Windows下“fatal: unable to checkout working tree, warning: Clone succeeded, but checkout failed.”
  14. NTFS分区和FAT32分区区别
  15. FIBOS社区发起人 响马:一个“极客硬核老炮儿”是怎样的?
  16. Oracle表空间(tablespaces)
  17. Apache Shiro 全面源码解析汇总
  18. iphone11官网HTML,苹果小白入手iPhone11,以下几个基础操作要知道
  19. 如何避免用户“漫天要价”和“就地还钱”
  20. 2018年全国多校算法寒假训练营练习比赛(第五场)F-The Biggest Water Problem

热门文章

  1. Cadence 计算器使用——settling time
  2. 前端页面设置重置按钮或刷新按钮
  3. 程序员的算法课(6)-最长公共子序列(LCS)
  4. js实现GeoHash算法
  5. mysql数据库表的多条件查询
  6. 串口、COM口、并口、RS232、USB
  7. 云计算与大数据处理技术_云计算与大数据处理
  8. 恢复出厂设置android手机号码,手机怎么恢复出厂设置 安卓手机恢复出厂设置方法汇总...
  9. C++报错信息:LNK2001:无法解析的外部符号 原因分析及解决方法
  10. Ubuntu+Windows双系统,默认从Windows启动