后端密码、Salt、IV的存储技术疑问及数据库存储方案咨询
对称加密技术问题解答
现有加密函数
async function encrypt(message: string) { const salt = randomBytes(16); const iv = randomBytes(16); const password = 'Password used to generate key'; const key = (await promisify(scrypt)(password, salt, 32)) as Buffer; const cipher = createCipheriv('aes-256-ctr', key, iv); const encryptedMessage = Buffer.concat([ cipher.update(message), cipher.final(), ]); return { encryptedMessage, iv, salt }; }
Node.js的crypto文档指出,密码、IV和Salt不应以字符串形式存储,而应存储为字节序列。结合对称加密知识,Salt和IV需要与加密消息一同存储,以下是针对问题的解答:
问题1:是否应将密码存储为字节序列?若可以,能否存储在.env文件中?若可行,具体格式是怎样的?
- 密码本身不需要直接存成字节序列,但用它派生密钥时,要确保用固定编码(如UTF-8)转成字节,避免编码不一致导致密钥生成错误。
- 可以存
.env,但绝对不能存明文密码!正确操作是:先用KDF(比如代码里的scrypt)把密码转换成32字节的密钥,再把密钥转成Base64字符串存在.env里。 - 具体格式:
.env中写ENCRYPTION_KEY=abcdefg12345...(Base64编码后的密钥),代码里读取后用Buffer.from(process.env.ENCRYPTION_KEY, 'base64')还原成Buffer类型的密钥。
问题2:如何在数据库中将Salt、IV和加密消息以字节形式存储?是否可将三者存储在同一字段,用特殊字符分隔?
- 数据库存储:主流数据库都支持二进制字段(比如MySQL的
BLOB、PostgreSQL的BYTEA、MongoDB的BinData),直接把Salt、IV、加密消息作为Buffer存入对应字段即可。 - 不建议用特殊字符分隔存同一字段:字节序列里可能出现和分隔符一样的字节,导致解密时拆分失败。推荐两种靠谱方案:
- 方案一:分三个独立的二进制字段存储,字段名比如
salt、iv、encrypted_message,逻辑清晰,不易出错。 - 方案二:把三者拼接成一个Buffer(顺序固定:前16字节是Salt,接下来16字节是IV,剩余部分是加密消息),存入单个二进制字段。解密时按固定长度拆分即可。
- 方案一:分三个独立的二进制字段存储,字段名比如
内容的提问来源于stack exchange,提问作者Shmookoff
相关产品推荐
相关产品推荐

