SoFunction
Updated on 2025-03-10

Share the JS front-end interface request parameter obfuscation scheme

Write in front

In some interface request scenarios, the data we want to carry does not want to be submitted in plain text, that is, some obfuscation or encryption processing is required for the parameters, and the backend will decrypt it after obtaining the data to obtain the real data.

The purpose is to protect the security of data and to raise the threshold for being revealed into plain text. For example, in the interface request for user login, if the account and password are transmitted in plain text, it will easily lead to some security problems. At the same time, we do not want anyone to forge parameters to initiate requests on the interface. Therefore, it is very necessary to confuse front-end parameters. Here is a self-use solution, which is the purpose of:

  • Prevent information leakage
  • Prevent parameters from being tampered with at will
  • Improve application security and stability

For the choice of encryption or obfuscation processing methods, e.g.base64MD5Algorithms with low security or irreversibility are not suitable for our scenario, but can be usedAesandRsaThe combination of the two can realize the encryption and decryption of data.

What interface parameters need to be processed

From a security perspective, it is unanimous here that as long as there are new additions, modifications, and deletion operations on the database, obfuscation/encryption is required. This type of interface is mostlypostputdeleteWait for a request.

And forgetIf the request is a standardized interface, it usually only obtains data and does not have direct operations on the database, so there is no need to do parameter processing.

Of course there ispostRequests and some file uploads, etc. do not want to be used for parameter processing interfaces, but require special processing, and in the development environment, in order to facilitate debugging, there is no need to be processed.

Parameter processing

becauseRsaWhen processing data is large, the advantages are not obvious, and it is suitable for processing scenarios with small data volume, so the processing of parameter data is adoptedAesEncryption, while participating in encryption keyskeyThen useRsaAsymmetric encryption improves cracking difficulty.

Related dependencies and version numbers involved:

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

The solution used here is to first process the original data asqueryString of form, then use it as a random string, participateAesEncrypt and intercept a specific string as the original key, and perform it againAesEncryption, and finally use the original key to use the public key agreed with the backendRsaThe specific process and algorithms for encryption processing are as follows:

  • Sort and extract parametersqueryString processing
  • Encrypt and intercept the extracted string using a random string to obtain the key
  • Use the key to perform the original parametersAesencryption
  • Make the keyRsaAsymmetric encryption
  • Output the finaldataandkey
/**
 * Encrypted request data
 * @param {Object} rawData
 * @returns {data, key}
 */
export function encryptRequestData(rawData) {
 // Dictionary sorting and assignment var result = {}, str = [], arr = (rawData).sort();
 (m => { result[m] = rawData[m] });
 // Process it into a query string for (var p in result)
     (p) && (encodeURIComponent(p) + "=" + encodeURIComponent(result[p]));
     result = ("&");
 // The key participating in Aes encryption will be symmetrically encrypted with 16-bit random codes, and then the 16-bit original key will be obtained from bit 3 const rawKey = aesEncrypt(result, randomString(16)).substr(3, 16);
 // Output the last encryption parameter const data = aesEncrypt((rawData), rawKey);
 const key = rsaEncrypt(rawKey);
 return { data, key }
}

Aes Encryption

/**
  * Aes Encryption
  * @param {String} data
  * @param {String} customer_key
  * @returns encrypted
  */
export function aesEncrypt(data, customer_key = "") {
    var key = .(customer_key);
    var messageHex = .(data);
    var encrypted = (messageHex, key, {
        "mode": ,
        "padding": .Pkcs7
    });
    return ();
}

Rsa Encryption

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

Signature verification

If further strengthening tamper protection is needed, a signature can be obtained through a certain algorithm when processing parameters.signThe value is submitted to the backend together. After the backend is decrypted, the decrypted data is generated by the same algorithm.signThe value is compared with the submitted one to determine whether it is a legal source of request. I will not give a detailed introduction here.

Processing timing

We need to obfuscate the parameters when requesting interception, here is only forpostRequest and non-local environments. In addition to the development environment, the instance has been added.uncryptTo identify which interfaces can not participate in processing.

// Request for interception(
    config => {
         = "application/x-www-form-urlencoded"
        const token = ('token')
        token && ( = token)
        const { method, uncrypt = false, data = {} } = config;
        (method === 'post' && !uncrypt && cfg.NODE_ENV === 'development') && ( = encryptRequestData(data));
        return config
    },
    error => (error)
)

Backend implementation

After the front-end parameters are processed,dataandkeyThe objects composed are submitted to the backend, and the service layer accepts them and decrypts them. Here, the implementation is taken as an example. Related dependencies and their version numbers:

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

Rsa decryption

// RSA decryptionrsaDecrypt(data) {
    let dataObj;
    return new Promise(function (resolve, reject) {
        // Store the private key in app/extend/pem/        ('app/extend/pem/', function (err, pem) {
            const key = new NodeRSA(pem, 'pkcs8-private');
            ({ encryptionScheme: 'pkcs1' });
            try {
                dataObj = (data, 'utf8');
            } catch (e) {
                const second = new NodeRSA(pem, 'pkcs8-private');
                try {
                    dataObj = (data, 'utf8');
                } catch (error) {
                    reject("Rsa decryption failed");
                }
            }
            resolve(dataObj);
        });
    });
}

Aes decryption

// Aes decryptionaesDecrypt(data, customer_key = "") {
    var key = .(customer_key || );
    var decrypt = (data, key, {
        "mode": ,
        "padding": .Pkcs7
    });
    return .(decrypt);
}

Handle middleware

Create a new middleware for decryption processingapp/middleware/

 = () => {
    return async function (ctx, next) {
        const { helper, request } = ctx;
        const { ajaxMsg } = helper;
        const { key, data } = ;
        if (!key || !data) return ajaxMsg(ctx, "-1", "Error request parameter", null, 400);
        let rawKey;
        try {
                rawKey = await (key);
        } catch (error) {
                return ajaxMsg(ctx, "-1", "Key resolution failed", null, 400)
        }
        if (!rawKey) return ajaxMsg(ctx, "-1", "Key resolution failed", null, 400);
        const decryptData = ((data, rawKey));
        if (!decryptData) return ajaxMsg(ctx, "-1", "Security verification failed", null, 400);
         = decryptData;
        await next();
    };
};

Used in routing

const { router, controller, middleware } = app;
const security = (); // Interface parameter encryption('/common/user/login', security, ); // Log in

The above is the detailed content shared by the JS front-end interface request parameter obfuscation scheme. For more information about JS front-end interface request parameter obfuscation, please pay attention to my other related articles!