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

 更新时间:2022年07月27日 14:22:45   作者:木亦Sam  
这篇文章主要为大家介绍了JS前端接口请求参数混淆方案分享,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
(福利推荐:【腾讯云】服务器最新限时优惠活动,云服务器1核2G仅99元/年、2核4G仅768元/3年,立即抢购>>>:9i0i.cn/qcloud

(福利推荐:你还在原价购买阿里云服务器?现在阿里云0.8折限时抢购活动来啦!4核8G企业云服务器仅2998元/3年,立即抢购>>>:9i0i.cn/aliyun

写在前面

在一些接口请求的场景中,我们希望携带的数据不希望是以明文的方式提交的,也就是需要对参数做一些混淆或者加密处理,后端拿到数据后再进行解密,得到真实数据。

其目的是为了保护数据的安全,以及提高被识破成明文的门槛。在例如用户登录的接口请求中,如果账号和密码是以明文传输的,会容易导致一些安全性问题,同时,我们也不希望谁都可以伪造参数对接口发起请求,因此前端参数混淆非常有必要,这里分享一个自用的方案,其目的在于:

  • 防止信息泄露
  • 防止参数被随意篡改
  • 提高应用安全性和稳定性

对于加密或者混淆的处理方式的选择,例如base64MD5等安全性不高或者不可逆的算法,不适用于我们这个场景,而是可以利用AesRsa两者结合的方式,实现数据的加解密。

什么接口的参数需要做处理

从安全角度出发,这里一致认为,只要是对数据库有新增、修改、删除操作的,一律需要做混淆/加密,这一类接口,多为postputdelete等请求。

而对于get请求,如果是规范化的接口,一般只是获取数据,不会对数据库有直接的操作,故不需要做参数处理。

当然还有post请求和一些文件上传等,不希望做参数处理的接口,需要特殊处理,以及在开发环境中,为了方便调试,也不需要做处理。

参数处理

因为Rsa在处理数据量较大时优势不明显,适合处理数据量较小的场景,所以对参数数据的处理采用了Aes加密,而参与加密的密钥key则采用Rsa非对称加密提高破解难度。

涉及到的相关依赖及其版本号:

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

这里使用的方案是,先将原始数据处理为query形式的字符串,然后将其使用随机字符串作为密钥,参与Aes加密,并截取特定的字符串,作为原始密钥,再进行一次Aes加密,最后将原始密钥使用与后端约定好的公钥进行Rsa加密处理,具体流程和算法如下:

  • 对参数排序、提取query字符串处理
  • 将提取的字符串利用随机字符串加密并截取,得到密钥
  • 利用密钥对原始参数进行Aes加密
  • 将密钥进行Rsa非对称加密
  • 输出最终的datakey
/**
* 加密请求数据
* @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)
)

后端实现

前端参数处理后以datakey组成的对象提交至后端,服务层接受后进行解密,这里以 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前端接口请求参数混淆的资料请关注程序员之家其它相关文章!

相关文章

  • js展示百度地图及添加标注实现

    js展示百度地图及添加标注实现

    这篇文章主要为大家介绍了js展示百度地图及添加标注实现示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08
  • 详细探究ES6之Proxy代理

    详细探究ES6之Proxy代理

    ES6中提出了一个新的特性,就是proxy,用来拦截在一个对象上的指定操作,这个功能非常的有用。本文会介绍 Proxy的使用方式及列举具体实例解释 Proxy 的使用场景。
    2016-07-07
  • vue axios请求超时的正确处理方法

    vue axios请求超时的正确处理方法

    这篇文章主要介绍了vue axios请求超时,设置重新请求的完美解决方法,一并给大家介绍了axios基本用法,需要的朋友可以参考下
    2018-04-04
  • Fabric.js 实现变换视窗示例详解

    Fabric.js 实现变换视窗示例详解

    这篇文章主要为大家介绍了Fabric.js 实现变换视窗示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-09-09
  • Javascript继承(上)——对象构建介绍

    Javascript继承(上)——对象构建介绍

    Javascript中除了基本数据(Undefined、Null、Boolean、Number、String),其他都是对象(Object)
    2012-11-11
  • JavaScript利用html5新方法操作元素类名详解

    JavaScript利用html5新方法操作元素类名详解

    这篇文章主要给大家分享的是JavaScript用html5新方法操作元素类名的详解,早先JavaScript处理起来特别不方便,需要先取到class属性,然后对字符串进行处理。现在html5给所有元素增加了classList属性来操作类属性,非常方便,下面就一起来看看具体操作过程吧
    2021-11-11
  • element?plus的样式修改和扩展实例

    element?plus的样式修改和扩展实例

    这篇文章主要为大家介绍了element?plus的样式修改和扩展实例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02
  • JavaScript 反射学习技巧

    JavaScript 反射学习技巧

    这篇文章主要给大家分享的是JavaScript 的反射学习技巧,主要是区别在于所有的函数对象属性过于复杂,而且额外增加可能会导致程序行为不合理,所以扩展 Reflect 函数来专门对函数对象处理调用方法,构造对象,获取或者设置属性等相关操作。下面一起进入文章内容吧
    2021-10-10
  • 微信小程序图片选择、上传到服务器、预览(PHP)实现实例

    微信小程序图片选择、上传到服务器、预览(PHP)实现实例

    这篇文章主要介绍了微信小程序图片选择、上传到服务器、预览(PHP)实现实例的相关资料,需要的朋友可以参考下
    2017-05-05
  • JS实现一个可以当镜子照的?Button

    JS实现一个可以当镜子照的?Button

    这篇文章主要介绍了JS实现一个可以当镜子照的?Button的方法示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03

最新评论

?


http://www.vxiaotou.com