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: ["*"]通配符,也无法匹配到合法的字符串类型算法值,因此抛出算法不允许的异常。 - 潜在问题:解密时使用通配符
*允许所有算法存在安全隐患,容易遭受算法混淆攻击;若传入解密函数的密文存在传输截断、多余转义问题,也会导致头部解析失败。
修复方案
- 修正加密阶段的头部配置,要么在自定义
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) } };
- 收紧解密阶段的算法允许列表,不要使用通配符,显式指定允许的算法,提升安全性:
var opts = { algorithms: ["RSA-OAEP-256"] };
- 校验传入解密函数的密文格式:标准compact JWE是由
.分隔的5段Base64URL字符串,确认密文在传输、存储过程中没有被截断、添加多余空格/换行、转义错误的问题。 - 实际使用时替换占位的测试密钥字符串,确保加载的公钥、私钥是匹配的合法PEM格式密钥对。
内容的提问来源于stack exchange,提问作者Amit
相关产品推荐
相关产品推荐

