前后端分离技术之加签,验签,防篡改

article/2025/10/7 13:28:36

上一篇讲解了加密解密,这次来个加签验签,实际项目里,我们采用的是react 和nodejs 来进行加签验签,用的jsrsasign库,下面贴点核心代码

 react加签

nodejs验签

 

实际应用在nodejs层可以将时间戳和sign签名验证通过剔除掉,所以对后端就是无感的。

下面来介绍下客户端见加签验签,前面的代码也有,以java为例

import org.apache.commons.codec.binary.Base64;import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
/*** @author ALvis* @ctreate 2019/11/26*/
public class RSACoder {public static final String KEY_ALGORITHM = "RSA";public static final String SIGNATURE_ALGORITHM = "MD5withRSA";public static byte[] decryptBASE64(String key) {return Base64.decodeBase64(key);}public static String encryptBASE64(byte[] bytes) {return Base64.encodeBase64String(bytes);}/*** 用私钥对信息生成数字签名** @param data       加密数据* @param privateKey 私钥* @return* @throws Exception*/public static String sign(byte[] data, String privateKey) throws Exception {// 解密由base64编码的私钥byte[] keyBytes = decryptBASE64(privateKey);// 构造PKCS8EncodedKeySpec对象PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);// KEY_ALGORITHM 指定的加密算法KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);// 取私钥匙对象PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);// 用私钥对信息生成数字签名Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);signature.initSign(priKey);signature.update(data);return encryptBASE64(signature.sign());}/*** 校验数字签名** @param data      加密数据* @param publicKey 公钥* @param sign      数字签名* @return 校验成功返回true 失败返回false* @throws Exception*/public static boolean verify(byte[] data, String publicKey, String sign)throws Exception {// 解密由base64编码的公钥byte[] keyBytes = decryptBASE64(publicKey);// 构造X509EncodedKeySpec对象X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);// KEY_ALGORITHM 指定的加密算法KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);// 取公钥匙对象PublicKey pubKey = keyFactory.generatePublic(keySpec);Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);signature.initVerify(pubKey);signature.update(data);// 验证签名是否正常return signature.verify(decryptBASE64(sign));}
}

下面是测试代码

public class Test2 {private static final String publicKey="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCHuKQKF9zgk3Y2OOeULroJnP4qHOGw/Jh/3+vKIqpXqZjjk2RW+eJLScHMWSxeZ+vwiboETGMlgSovywQN7qph6r10btW/V6B1PvHZr57N1nJ1MxtrIWKKYJKVUMZtwkhGes65YtZ7rMDMvCRas/3sP8NixHV8RYNm/KrnMknoAQIDAQAB";private static final String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIe4pAoX3OCTdjY455Quugmc/ioc4bD8mH/f68oiqlepmOOTZFb54ktJwcxZLF5n6/CJugRMYyWBKi/LBA3uqmHqvXRu1b9XoHU+8dmvns3WcnUzG2shYopgkpVQxm3CSEZ6zrli1nuswMy8JFqz/ew/w2LEdXxFg2b8qucySegBAgMBAAECgYBW9BEE9mzo5REjhCm6YoWGizK7wG1Ie00pAEmM49DHAT2W8GOk5cv5+HNVfPxUL7iWD2dCQb5z1OE2ZZdfZb16q9YdAXxTt90exoDX8q4i0xWTKPooVni8+tdypzizw0m3XN/adq6RC4Hz8Xc5n6RTl+1rAGc60AkTmmhZaAx0EQJBAP6+yegOa9uQS06ww+pWZKO+hm3kIPunIkYlN3Y7KkPCOJq4WiS7D/oIyBYIBG/UltloF3ROOIf3uMROvdcvlE8CQQCIY8X3ICn5p+Ot32V/ZhT0aebUKGFvG9b/Zx072xEumG0xIhtOic1Vr10hvPYckWbJcEY6s+oeiXzi9CwutJqvAkEA4N+SZCK2228YyzIG/8mbtV/uUvtakksLWlhoCRpZSM8eIJY0HNB0Xgd6eNhC8mT7dJcKfUS/amcm10ObGWWKyQJATo/aGk1GoG3ase66UjYE3/yYX6Ca7xtELn3A0xeOwB5A10pkHEs4IaEPrj1gLnh6kpG/glTcCJb9fuVTBdw2NQJALFt2PMr8PwPKnV74MZFcKGlF7Qz31SIAPBgClsS/bUweJ/3lw9Xopv0WO8INdSqgwjAX2+PjDwOiwBYtD7bPNw==";@Testpublic void test1() throws Exception{EvalUser user = new EvalUser();user.setUserid("001");user.setUsername("alvis");user.setOrgId("111");user.setLevel("222");String content = JSON.toJSONString(user);String sign = RSACoder.sign(content.getBytes(), privateKey);String lastSign = URLEncoder.encode(sign.replace("\n", ""), "UTF-8");System.out.println("签名内容:" + content);System.out.println("最终签名:" + lastSign);// 签名验证String test ="{\"level\":\"222\",\"orgId\":\"111\",\"userid\":\"001\",\"username\":\"alvis\"}";boolean bverify = RSACoder.verify(test.getBytes(), publicKey, URLDecoder.decode(lastSign, "UTF-8"));System.out.println("验证结果:" + bverify +";decode sign="+URLDecoder.decode(lastSign, "UTF-8"));}
}

加签验签一般失败的原因就是json转换时的顺序,比如用fastjson转换成字符串加签,那么解签时就要注意,把json转成字符串的排序是否一致,同是fastjson排序规则也会随着版本的改变而不同,解决方案之一就是要么用同版本的工具,要么可以结合加密解密来进行。


http://chatgpt.dhexx.cn/article/JembxFaH.shtml

相关文章

深入探究Camunda加签问题

开源项目介绍:点击直达 前言 这里我们先抛出两个大问题,整篇文章针对这两个大问题再详细解析。 首先我们在设计流程定义时,流程节点可能是或签也可能是会签 会签:指同一个审批节点设置多个人,如ABC三人&#xff0c…

activity多实例任务加签

前言 加签是减签的相反的操作,加签与减签的思路刚好相反,减签是删数据;加签则是添加数据。在一些特殊场景下,需要在某个多实例节点上面动态新增一个审批人员或任务时,就需使用到activity多实例任务加签的功能 加签思路1 根据一级流程实例查找二级流程执行实例判断二级执…

Activiti7工作流引擎:进阶篇(十二) 加签和转签

知识传送门 》》》》》》》》》》》》》》》》》》》 加签就是委派任务delegateTask,然后去解决任务resolveTask(并不是去真正的去完成任务)。转签完成后才能完成任务complete。 一:委派任务 A由于某些原因不能处理该任务可以把任…

必备基础:加签验签

必备基础:加签验签 1 密码学相关概念1.1 明文、密文、密钥、加密、解密1.2 对称加密、非对称加密1.3 什么是公钥私钥? 2 加签验签概念3 为什么需要加签验签4 常见加密相关算法简介4.1 消息摘要算法4.1.1 MD家族算法4.1.2 ShA家族算法4.1.3 MAC算法家族 4…

Flowable工作流之加签(委派)、转签(转办)

目录 1. 加签1.1. 向前加签1.2. 向后加签 2. 或签3. 委派和转办的区别2.1. 委派2.2. 转办 4. 向前加签4.1. 流程图4.2. 部署并启动4.3. 完成任务4.4. 向前加签实现4.4.1. 添加加签(委派)功能任务4.4.1. 加签(委派)任务的完成 5. 转…

加密、解密、加签、验签专题

首先明确几个名词: 加密:发送方利用接收方的公钥对要发送的明文进行加密。 解密:接受方利用自己的私钥进行解密。 公钥和私钥配对的,用公钥加密的文件,只有对应的私钥才能解密。当然也可以反过来,用私钥…

@ControllerAdvice 之 @InitBinder和@ModelAttribute

InitBinder 准备 InitBinder 在整个 HandlerAdapter 调用过程中所处的位置 收获💡 RequestMappingHandlerAdapter 初始化时会解析 ControllerAdvice 中的 InitBinder 方法(可以定义个性化数据转化器)RequestMappingHandlerAdapter 会以类…

SpringBoot @InitBinder注解实现Bean国际化校验

参考资料 参考: 妥当性チェックのエラーメッセージ出力方法 (需翻墙)springMVC之InitBinder的用法1springMVC之InitBinder的用法2springMVC之InitBinder 和 ValidatorSpring MVCにおけるフォームバリデーションの適用事例【後編】 目录 一. 前期准备1.1 自定义校验…

SpringMVC之@InitBinder注解(日期转换)

InitBinder注解的作用: springmvc并不是能对所有类型的参数进行绑定的,如果对日期Date类型参数进行绑定,就会报错IllegalStateException错误。所以需要注册一些类型绑定器用于对参数进行绑定。InitBinder注解就有这个作用。 程序代码示例&am…

initbinder对ajax不起作用,Spring MVC InitBinder验证方法

使用InitBinder做验证的情况一般会在此Controller中提交的数据需要有一些是业务性质的,也即比较复杂的验证情况下才会使用。大部份简单的表单验证,使用annotation验证即可以解决。 这里需要注意的一点:InitBinder和Annotation两种验证只能二选…

SpringMvc @InitBinder

这篇博客记录InitBinder怎么起作用、起什么作用? 首先,该注解被解析的时机,是该匹配Controller的请求执行映射的方法之前; 同时 InitBinder标注的方法执行是多次的,一次请求来就执行一次。 当某个Controller上的第一次请求由SpringMvc前端控制…

java培训之InitBinder注解

InitBinder注解【了解】 InitBinder由 InitBinder 标识的方法,可以对 WebDataBinder 对象进行初始化。WebDataBinder 是 DataBinder 的子类,用于完成由表单字段到 JavaBean 属性的绑定InitBinder方法不能有返回值,它必须声明为void。InitBin…

SpringBoot @InitBinder注解绑定请求参数

参考资料 springMVC之InitBinder 和 ValidatorspringMVC之InitBinder的用法1springMVC之InitBinder的用法2 目录 一. 作用二. 前期准备三. Get请求 URL传值处理3.1 前台-test16.html3.2 Controller层3.3 效果 四. Post请求 表单传值 自定义日期属性绑定器4.1 前台-test16.h…

详细分析@InitBinder注解的使用和原理

前言 由InitBinder注解修饰的方法用于初始化WebDataBinder对象,能够实现:从request获取到handler方法中由RequestParam注解或PathVariable注解修饰的参数后,假如获取到的参数类型与handler方法上的参数类型不匹配,此时可以使用初…

SpringMVC之@InitBinder注解详解

说明与作用 springmvc并不是能对所有类型的参数进行绑定的,如果对日期Date类型参数进行绑定,就会报错IllegalStateException错误。所以需要注册一些类型绑定器用于对参数进行绑定。InitBinder注解就有这个作用。 Controller public class InitBinderCo…

SpringMVC中的@InitBinder注解【记录】

一、Spring请求参数绑定流程: 1、请求参数绑定流程: 我们在开发的时候,经常会从html,jsp中将请求参数通过request对象传递到后台,可是经常会遇到这么一种情况,那就是传过来的数据到后台后,还要…

springMVC之@InitBinder的用法

目录 一、InitBinder的作用二、数据绑定器三、全局数据绑定器3.1. 方式一:ControllerAdvice3.2. 方式二:RequestMappingHandlerAdapter 四、自定义数据校验器五、参数类型转换器 一、InitBinder的作用 InitBinder从字面意思可以看出这个的作用是给Binder…

JAVA-Switch语句

1、完整的语法结构 该语句为选择分支语句,其语法结构为: switch (值){case:值1 java语句;break;case:值2 java语句;break;case:值3 java语句;break;……default:java语句; } 注意在该语法结构中,“值N"可以表示int型的或者S…

java中的常用语句

Java中的常用语句 一、Java中的语句由3大类的结构 1.顺序结构—自上而下一行一行的有序的执行 2.选择结构 (1)If语句结构 (2)Switch语句结构 3.循环结构 (1)For循环 (2)While循环 (3)Do{}while()循环 二、判断语句中if语句的表现方式和用法 1.if(){} 2.if(){}else{} 3.if(){}e…

4.java中的常见语句

1.顺序结构语句 写好的代码从上往下按照顺序一行一行的执行。 2.选择结构语句 根据判断结果有选择性的执行代码. 2.1 if语句 1.if(判断条件){需要执行的java代码} 首先执行判断条件,如果判断条件的结果为true,就执行“{}”中的java代码&#x…