如何在MongoDB中正确存储/读取AWS KMS加密的Token?
解决AWS KMS加密数据MongoDB存储与读取的问题
问题根源:KMS返回的CiphertextBlob是Uint8Array(ArrayBuffer的视图类型),直接存MongoDB会被自动序列化为带type和data字段的普通对象,取出后不再是ArrayBuffer类型,导致KMS解密时参数不合法。
正确处理流程
1. 加密后转Base64字符串存储
修改加密函数,把返回的Uint8Array转成Base64字符串,MongoDB存储标准字符串就不会丢失类型信息:
export const encryptToken = async (token) => { const uint8array = new TextEncoder().encode(token); const encryptCommand = new EncryptCommand({ KeyId: KMS_KEY_NAME, Plaintext: uint8array, }); const response = await client.send(encryptCommand); // 将Uint8Array转为Base64字符串 return Buffer.from(response.CiphertextBlob).toString('base64'); };
2. 读取时把Base64转回Uint8Array
修改查询逻辑,把从MongoDB取出的Base64字符串转回Uint8Array,再传给解密函数:
export const getOpenAIKey = async (orgId) => { const docs = await (await queryDatabase(COLLECTION_NAME, { orgId })).toArray(); if (!docs.length) { throw new Error(`Credentials not found for ${orgId}`); } // 对应插入时的字段名encryptedKey,原代码取key是错误的 const encryptedKeyBase64 = docs[0].encryptedKey; // 把Base64转回Uint8Array return Uint8Array.from(Buffer.from(encryptedKeyBase64, 'base64')); };
3. 解密函数无需修改
KMS的DecryptCommand原生支持Uint8Array作为CiphertextBlob参数,原解密函数可以直接使用:
export const decryptToken = async (cipher) => { const decryptCommand = new DecryptCommand({ KeyId: KMS_KEY_NAME, CiphertextBlob: cipher, }); const response = await client.send(decryptCommand); const token = new TextDecoder().decode(response.Plaintext); return token; };
额外修正点
- 插入函数里的
encryptToken(Key)要改成encryptToken(openaiKey),原变量名拼写错误会导致报错; - 插入时存储的字段是
encryptedKey,查询时必须对应取该字段,原代码取docs[0].key会拿到undefined。
内容的提问来源于stack exchange,提问作者EvyatarDot
相关产品推荐
相关产品推荐

