JS前端接口请求参数混淆方案分享

作者:沉舟时间:2026-10-25 16:48:53浏览:383

本文介绍一种JS前端接口请求参数混淆方案,采用AES对称加密处理数据,结合RSA非对称加密保护密钥,防止信息泄露与参数篡改。方案适用于Post、Put、Delete等修改数据库的接口,通过请求拦截器在发送前处理,后端使用Egg.js中间件解密验证,提升应用安全性。

前言

在部分接口调用场景中,为规避数据以明文形式传输,需对请求参数实施混淆或加密措施,由服务端接收后执行解密以还原原始信息。

此举旨在保障数据安全并增加明文破解难度。以用户登录接口为例,若账号密码明文传输易引发安全隐患,且需防范参数伪造请求,故前端参数混淆至关重要,本文分享一种个人实践方案,主要目标包括:

  • 规避信息泄露风险
  • 阻断参数被非法篡改
  • 增强应用整体安全性与稳定性

针对加密或混淆算法的选择,诸如base64、MD5等安全性较低或不可逆的算法不符合本场景需求,应采用Aes与Rsa相结合的策略,以达成数据加解密目标。

需处理的接口参数范围

基于安全考量,凡涉及数据库新增、修改或删除操作的接口,均须执行混淆或加密处理,此类接口通常表现为post、put、delete等请求类型。

针对get请求,若接口设计规范,仅用于数据获取且无数据库直接操作,则无需进行参数处理。

此外,post请求及部分文件上传等无需参数处理的接口需特殊对待;同时,在开发环境中为便于调试,亦无需执行处理。

参数处理机制

鉴于Rsa在处理大规模数据时优势不显著,适用于小数据量场景,故参数数据处理选用Aes加密,而参与加密的密钥key则通过Rsa非对称加密技术提升破解难度。

相关依赖库及其版本号如下:

"crypto-js": "^4.1.1", "jsencrypt": "^3.2.1"

本方案流程为:先将原始数据转换为query格式字符串,随后以随机字符串作为密钥进行Aes加密,截取特定子串作为原始密钥,再次执行Aes加密,最终利用与后端约定的公钥对原始密钥进行Rsa加密。具体流程及算法如下:

  • 对参数排序并提取query字符串进行处理
  • 利用随机字符串加密提取的字符串并截取,生成密钥
  • 使用生成的密钥对原始参数执行Aes加密
  • 对密钥实施Rsa非对称加密
  • 输出最终的data与key
/**
* 加密请求数据
* @param {Object} rawData 原始数据
* @returns {data, key}
*/
export function encryptRequestData(rawData) {
 // 字典排序并赋值
 var result = {}, str = [], arr = Object.keys(rawData).sort();
 arr.map(m => { result[m] = rawData[m] });
 // 处理成 query 形式字符串
 for (var p in result)
     result.hasOwnProperty(p) && str.push(encodeURIComponent(p) + "=" + encodeURIComponent(result[p]));
     result = str.join("&");
 // 参与 Aes 加密的密钥,将处理后的字符串用 16 位随机码对称加密,再从第 3 位开始获取 16 位原始密钥
 const rawKey = aesEncrypt(result, randomString(16)).substr(3, 16);
 // 输出最后的加密参数
 const data = aesEncrypt(JSON.stringify(rawData), rawKey);
 const key = rsaEncrypt(rawKey);
 return { data, key }
}

Aes加密实现

/**
 * Aes 加密
 * @param {String} data
 * @param {String} customer_key
 * @returns encrypted
 */
export function aesEncrypt(data, customer_key = "") {
    var key = CryptoJS.enc.Utf8.parse(customer_key);
    var messageHex = CryptoJS.enc.Utf8.parse(data);
    var encrypted = CryptoJS.AES.encrypt(messageHex, key, {
        "mode": CryptoJS.mode.ECB,
        "padding": CryptoJS.pad.Pkcs7
    });
    return encrypted.toString();
}

Rsa加密实现

/**
 * Rsa 加密
 */
export function rsaEncrypt(rawData) {
    let data;
    try {
        var rsa = new JsEncrypt();
        rsa.setPublicKey(publicPem);
        data = rsa.encrypt(rawData)
    } catch (error) {
        return null
    }
    return data;
}

签名验证机制

若需进一步强化防篡改能力,可在参数处理过程中通过特定算法生成签名sign值并随请求提交。后端解密后,利用相同算法对解密数据生成sign值并与提交值比对,以验证请求合法性。此处不作深入展开。

处理时机控制

需在请求拦截阶段对参数执行混淆处理,仅针对post请求及非本地环境生效。为便于调试,除开发环境外,在实例配置中增加了uncrypt标识,用于指定无需处理的接口。

// 请求拦截
instance.interceptors.request.use(
    config => {
        config.headers.contentType = "application/x-www-form-urlencoded"
        const token = local.get('token')
        token && (config.headers.Authorization = token)
        const { method, uncrypt = false, data = {} } = config;
        (method === 'post' && !uncrypt && cfg.NODE_ENV === 'development') && (config.data = encryptRequestData(data));
        return config
    },
    error => Promise.error(error)
)

后端实现逻辑

前端处理后的参数以data和key构成的对象形式提交至后端,服务层接收后执行解密。此处以Egg.js框架实现为例。涉及依赖及其版本号如下:

"crypto-js": "^4.1.1", "node-rsa": "^1.1.1"

Rsa解密实现

// RSA 解密
rsaDecrypt(data) {
    let dataObj;
    return new Promise(function (resolve, reject) {
        // 私钥存放在app/extend/pem/private.pem
        fs.readFile('app/extend/pem/private.pem', function (err, pem) {
            const key = new NodeRSA(pem, 'pkcs8-private');
            key.setOptions({ encryptionScheme: 'pkcs1' });
            try {
                dataObj = key.decrypt(data, 'utf8');
            } catch (e) {
                const second = new NodeRSA(pem, 'pkcs8-private');
                try {
                    dataObj = second.decrypt(data, 'utf8');
                } catch (error) {
                    reject("Rsa 解密失败");
                }
            }
            resolve(dataObj);
        });
    });
}

Aes解密实现

// Aes 解密
aesDecrypt(data, customer_key = "") {
    var key = CryptoJS.enc.Utf8.parse(customer_key || this.config.secret.aes.key);
    var decrypt = CryptoJS.AES.decrypt(data, key, {
        "mode": CryptoJS.mode.ECB,
        "padding": CryptoJS.pad.Pkcs7
    });
    return CryptoJS.enc.Utf8.stringify(decrypt);
}

处理中间件配置

新建解密处理中间件app/middleware/security.js

module.exports = () => {
    return async function (ctx, next) {
        const { helper, request } = ctx;
        const { ajaxMsg } = helper;
        const { key, data } = request.body;
        if (!key || !data) return ajaxMsg(ctx, "-1", "请求参数错误", null, 400);
        let rawKey;
        try {
                rawKey = await helper.rsaDecrypt(key);
        } catch (error) {
                return ajaxMsg(ctx, "-1", "密钥解析失败", null, 400)
        }
        if (!rawKey) return ajaxMsg(ctx, "-1", "密钥解析失败", null, 400);
        const decryptData = JSON.parse(helper.aesDecrypt(data, rawKey));
        if (!decryptData) return ajaxMsg(ctx, "-1", "安全验证未通过", null, 400);
        request.body = decryptData;
        await next();
    };
};

路由中使用方式

const { router, controller, middleware } = app;
const security = middleware.security(); // 接口参数加密
router.post('/common/user/login', security, controller.common.user.login); // 登录

以上为JS前端接口请求参数混淆方案的完整内容,更多JS前端接口请求参数混淆相关信息请关注本站其他文章!

作者最新文章
相关文章
更多