You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js使用node-jose解密JWT报Algorithm not allowed: undefined错误

问题描述

在Node.js项目中使用node-jose库处理JWE加密的JWT令牌时,加密流程可正常运行,解密流程抛出异常,错误信息如下:

{
  "message": "Algorithm not allowed: undefined",
  "stack": "Error: Algorithm not allowed: undefined\n    at /myproject/test/wallet/node_modules/node-jose/lib/jwe/decrypt.js:146:37\n    at <anonymous>\n    at process._tickCallback (internal/process/next_tick.js:160:7)",
  "level": "error"
}

问题相关核心实现代码如下:

const jose = require('node-jose');

exports.encrypt = async function (jwtToken) {
    if (jwtToken && jwtToken != null && jwtToken != undefined && jwtToken != "") {
        const pubKey = "sdf#!@!$dsfdtestdsfsdfdsfdsf&^%sdfdfsd"
        try {
            let encryptionKey = await jose.JWK.asKey(pubKey, 'pem', { alg: 'RSA-OAEP-256' });
            let contentAlg = 'A256GCM';
            let options = {
                contentAlg: contentAlg,
                compact: true,
                fields:
                {
                    'iat': Math.round(new Date().getTime() / 1000)
                }
            };
            var encryptedData = await jose.JWE.createEncrypt(options, encryptionKey).update(Buffer.from(jwtToken, 'utf8')).final();
            if (encryptedData) {
                return Promise.resolve(encryptedData);
            }
        } catch (err) {
            return Promise.reject(err);
        }     
    }
};

exports.decrypt = async function (encryptedToken) {
        if (encryptedToken && encryptedToken != null && encryptedToken != undefined && encryptedToken != "") {
            const priKey = "DAG$$fh$%341212(*&^%$sdhfksdhfdsfsdfsd";
            try {
                var opts = {
                    algorithms: ["*"]
                  };
                let decryptionKey = await jose.JWK.asKey(priKey, 'pem', { alg: 'RSA-OAEP-256', enc: 'A256GCM' });
                const decryptedToken = await jose.JWE.createDecrypt(decryptionKey, opts).decrypt(encryptedToken);
                if (decryptedToken) {
                    return Promise.resolve(decryptedToken.plaintext.toString());
                }
            } catch (err) {
                return Promise.reject(err);
            } 
        }
    };
报错原因
  • 核心原因是加密阶段头部配置错误:在加密配置中传入的自定义fields对象仅包含iat字段,node-jose会将传入的fields作为完整的JWE受保护头部使用,不会自动合并默认必填的alg(密钥加密算法)、enc(内容加密算法)字段,导致最终生成的JWE密文头部缺失算法声明。
  • 解密阶段解析JWE头部时,读取到的alg值为undefined,即使配置了algorithms: ["*"]通配符,也无法匹配到合法的字符串类型算法值,因此抛出算法不允许的异常。
  • 潜在问题:解密时使用通配符*允许所有算法存在安全隐患,容易遭受算法混淆攻击;若传入解密函数的密文存在传输截断、多余转义问题,也会导致头部解析失败。
修复方案
  1. 修正加密阶段的头部配置,要么在自定义fields中显式补全alg和enc字段,要么去掉不必要的JWE头部自定义(iat属于JWT标准声明,放在JWT的payload中即可,无需放在JWE外层头部)。
    修正后的加密配置示例:
let options = {
    contentAlg: contentAlg,
    compact: true,
    fields: {
        // 显式补全算法字段,避免被自定义配置覆盖
        alg: 'RSA-OAEP-256',
        enc: contentAlg,
        'iat': Math.round(new Date().getTime() / 1000)
    }
};
  1. 收紧解密阶段的算法允许列表,不要使用通配符,显式指定允许的算法,提升安全性:
var opts = {
    algorithms: ["RSA-OAEP-256"]
};
  1. 校验传入解密函数的密文格式:标准compact JWE是由.分隔的5段Base64URL字符串,确认密文在传输、存储过程中没有被截断、添加多余空格/换行、转义错误的问题。
  2. 实际使用时替换占位的测试密钥字符串,确保加载的公钥、私钥是匹配的合法PEM格式密钥对。

内容的提问来源于stack exchange,提问作者Amit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 04:48:17