在后端存储密码、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 };
}

以及crypto文档中的这一部分,据说密码、IV和salt不应存储为字符串,而应存储为字节序列。

根据我对对称加密的了解,我必须将salt和初始化向量与加密消息一起存储。

我想问的问题是:

  • 我应该将密码存储为字节序列吗?如果是,我可以将其存储在.env文件中吗?如果是的话,会是什么样子
  • 如何将salt、IV和加密消息作为字节存储在数据库中?是否可以存储在一个字段中,用一些特殊字符分隔

您误解了这里的文档,它说通常使用字符串不是传输字节数组的好方法,因为字符串有很多编码,其中一些编码无法表示所有可能的字节序列,即UTF-8,它是为可读文本而非随机字节序列创建的。

然而,有些编码是为了将字节数组安全地编码为ascii字符(如base64或hex(而创建的,因此您可以使用它们对消息进行编码。例如:

async function encrypt(message) {
const salt = randomBytes(16);
const iv = randomBytes(16);
const password = 'Password used to generate key';

const key = (await promisify(scrypt)(password, salt, 32));
const cipher = createCipheriv('aes-256-ctr', key, iv);

let encryptedMessage = cipher.update(message, 'utf8', 'hex');
encryptedMessage += cipher.final('hex');

return `${encryptedMessage}:${iv.toString('hex')}:${salt.toString('hex')}`;
}

然后,结果字符串可以像这样存储在一个数据库字段中,您可以稍后通过以下操作恢复缓冲区:

let encryptedMessage = Buffer.from(message_part, "hex");
const iv = Buffer.from(iv_part, "hex");
const salt = Buffer.from(salt_part, "hex");

关于.env,我不确定你的意思。密码是一个普通字符串,因此您可以简单地将其存储在.env文件中,如下所示:

CRYPTO_PASSWORD="Password used to generate key"

然后使用dotenv包像这样加载:

import * as dotenv from 'dotenv'
dotenv.config()
...
const password = process.env.CRYPTO_PASSWORD;

我认为您误解了文档中的内容。它所说的只是,在与lib交互时,应该使用原始字节数组,而不是字符串。因为两个原因:

  1. 如果将字符串传递给lib,它将被转换为字节数组,并且这个过程通常会降低熵(例如,随机utf-8字符串不如随机字节序列随机(,并导致密码的加密性能较差
  2. 并不是每个字节序列都是utf-8字符串,因此输出到字符串的默认转换并不总是可能的。当然,还有其他方式

但这与存储数据的内容和方式无关

我应该将密码存储为字节序列吗?

您可以随心所欲地存储密码。也就是说,密码(与salt、iv和加密消息不同(通常由用户以字符串而不是原始字节的形式提供。因此,我认为将它们转换为字节数组没有任何好处。

如果是,我可以将其存储在.env文件中吗?如果是的话,会是什么样子?

当然可以。如果你指的是标准的env文件,那么简单的

PASSWORD="my password"

我不知道你在这里是什么意思?

如果你想在这里放一个字节序列,那么你必须把它编码成一个字符串。一种方法是使用base64编码。另一种是使用十六进制编码。但是,你当然需要在你的应用程序中添加一个额外的逻辑来进行解码。

如何将salt、IV和加密消息作为字节存储在数据库中?是否可以存储在一个字段中,用一些特殊字符分隔?

将它们全部放在一个字段中需要一些分离逻辑。由于该数据可能具有任何字节序列,因此没有可以用作分隔符的特殊字符。因此您有以下选项:

  1. 将所有数据编码为例如base64或hex,然后用编码未使用的字符将它们连接起来。例如,对于base64和hex,:字符都可以工作
  2. 将它们放入单独的字段中

解决方案2。可能更高效(尤其是如果数据库支持二进制格式(,并且可能占用更少的空间(总是度量(。我鼓励你们这样做。我认为将这些数据存储在一个字段中没有多大好处。

最新更新