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

1.场景

最近项目上被渗透扫到可以通过篡改后端返回的报文,来使前端跳过校验进入下一步操作

2.解决方法

通过后端RSA非对称加密方式,对返回的数据使用私钥进行加密,增加返回参数sign,前端使用公钥来对相同的数据加密,通过对比生成的sign来判断数据是否存在篡改的情况。

1.前端引入依赖
javascript 复制代码
"node-forge": "^1.3.0"
2.生成一对秘钥,前端存放公钥,后端存放私钥
javascript 复制代码
const forge = require('node-forge');
const pki = forge.pki;
// 生成 RSA 密钥对 (512 位)
const keys = pki.rsa.generateKeyPair(512);
// 将私钥转换为 PEM 格式
const privateKeyPem = pki.privateKeyToPem(keys.privateKey);
console.log('Private Key (PEM):\n', privateKeyPem);
// 将公钥转换为 PEM 格式
const publicKeyPem = pki.publicKeyToPem(keys.publicKey);
console.log('Public Key (PEM):\n', publicKeyPem);
3.后端使用私钥对数据进行加密
3.1工具类
java 复制代码
public class RSAUtil {

    /**
     * 获取公钥
     * 
     * @param publicKey 公钥字符串
     * @return
     */
    public static PublicKey getPublicKey(String publicKey) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        byte[] decodedKey = Base64.decodeBase64(publicKey.getBytes());
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedKey);
        return keyFactory.generatePublic(keySpec);
    }
    /**
     * 签名
     * 
     * @param data 待签名数据
     * @param privateKey 私钥
     * @return 签名
     */
    public static String sign(String data, PrivateKey privateKey) throws Exception {
        byte[] keyBytes = privateKey.getEncoded();
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey key = keyFactory.generatePrivate(keySpec);
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(key);
        signature.update(data.getBytes());
        return new String(Base64.encodeBase64(signature.sign()));
    }

    /**
     * 验签
     * 
     * @param srcData 原始字符串
     * @param publicKey 公钥
     * @param sign 签名
     * @return 是否验签通过
     */
    public static boolean verify(String srcData, PublicKey publicKey, String sign) throws Exception {
        byte[] keyBytes = publicKey.getEncoded();
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey key = keyFactory.generatePublic(keySpec);
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initVerify(key);
        signature.update(srcData.getBytes());
        return signature.verify(Base64.decodeBase64(sign.getBytes()));
    }
3.2后端使用私钥加密数据,生成sign一并返回前端
java 复制代码
		Boolean flag = (Boolean) map.get("flag");
        Long timeStamp = System.currentTimeMillis();
        stringMap.put("flag", String.valueOf(flag));
        //签名的生成增加时间戳
        stringMap.put("timeStamp", String.valueOf(timeStamp));
        //使用私钥进行签名生成
        String signature = RSAUtil.sign(JSON.toJSONString(stringMap), RSAUtil.getPrivateKey(SystemHashMap.systemHashMap.get("YDSC_ORDER_RSA_PRIVATE_KEY")));
        map.put("timeStamp", timeStamp);
        map.put("signature", signature);
4.前端进行加密相同数据验签
4.1.对后端返回的数据使用公钥加密,验签
javascript 复制代码
verifySignature(response) {
      const json = {
        flag: response.flag,
        timeStamp: response.timeStamp,
      };
      const data = JSON.stringify(json);
      const md = forge.md.sha256.create();
      md.update(data, 'utf8');
      //验签
      const signature = forge.util.decode64(response.signature);
      // 将PEM格式的公钥转换为Forge公钥对象
      const publicKey = forge.pki.publicKeyFromPem(this.publicKey);
      // 验证签名
      const verified = publicKey.verify(md.digest().bytes(), signature);
      return verified;
    }
相关推荐
gugucoding6 分钟前
57. 【Java】日志框架:SLF4J与Logback
java·开发语言·logback
今天的砖头有点烫手啊7 分钟前
JVM 调优实战:从 GC 日志到参数优化,一次完整排查
java·jvm
爱奥尼欧27 分钟前
10.C++ string 实现详解
java·开发语言·c++
小飞学编程...29 分钟前
【equals 、Comparable、Comparator 三者的区别】
java·python
骇客野人37 分钟前
Java分布式任务调度方案(完整落地指南)
java·开发语言·分布式
JacksonMx43 分钟前
Spring @Async 坑点 + 改造方案
java·开发语言
Dovis(誓平步青云)1 小时前
牛奶不能减成负数:冰箱库存的筛选、去重与不可变更新
android·java·开发语言
SWAGGY..2 小时前
【C++初阶】:(15)模板进阶--从非类型参数到模板特化与分离编译
java·服务器·前端
楠楠子呀2 小时前
独立站聊天转化全链路:从二维码引流到数据复盘
java·javascript·数据仓库·python·c#·自动化·etl
yurenpai(27届找实习中)2 小时前
从零读懂AI智能客服(二):Java 多模块项目如何协作:Maven 依赖、Spring 注入与运行时装配
java·spring·maven