为何传入不同字符串的两个Node.js Buffer却相等?
问题:不同密钥字符串生成的Buffer相等,导致JWE解密验证意外通过
你的问题核心出在Buffer.alloc()的用法错误,导致不同的密钥字符串生成了完全相同的Buffer,自然能解密同一个JWE。
原因分析
Buffer.alloc(32, process.env.SECRET_KEY) 的第二个参数是「填充值」,不是用来初始化Buffer的完整字符串:
- 当你传入字符串作为填充值时,Node.js只会取这个字符串的第一个字符的Unicode编码,用这个字节重复填充整个32字节的Buffer。
- 比如如果你的
SECRET_KEY和INVALID_SECRET的第一个字符相同(比如都是s),那么生成的两个Buffer会完全一致,equals()自然返回true。 - 哪怕两个字符串第一个字符不同,这种方式生成的Buffer也不是你期望的「将密钥字符串转成字节序列」的结果,而是用单个字符重复填充的Buffer,完全不符合对称密钥的要求。
正确的密钥生成方式
要将字符串转换成对应的字节Buffer,应该使用Buffer.from()方法,它会将字符串按指定编码(默认UTF-8)转换成字节序列:
// 生成加密密钥 const secret = Buffer.from(process.env.SECRET_KEY, 'utf8'); // 生成解密用的无效密钥 const secretWithInvalidString = Buffer.from(process.env.INVALID_SECRET, 'utf8');
额外注意事项
因为你使用的是A256GCM加密算法,要求密钥必须是256位(32字节)。如果你的环境变量中的密钥字符串转成字节后长度不是32字节,会导致JOSE库报错。这种情况下,建议用密钥派生函数(比如HKDF)从字符串生成符合长度要求的密钥:
const { createHmac } = require('crypto'); // 从字符串派生32字节的对称密钥 function deriveKey(inputKey) { // 可添加盐值(salt)和信息(info)增强安全性 return createHmac('sha256', inputKey).digest().slice(0, 32); } const secret = deriveKey(process.env.SECRET_KEY); const secretWithInvalidString = deriveKey(process.env.INVALID_SECRET);
内容的提问来源于stack exchange,提问作者Gleb Gaiduk
相关产品推荐
相关产品推荐

