Sequelize使用随机IV加密字段后查询失败的解决方案咨询
问题1:保留随机IV的前提下实现加密字段查询的方案
可以采用密文哈希索引的方案实现,具体逻辑如下:
- 给对应数据表新增独立的索引字段,例如命名为
myField_hash,字段类型设为VARCHAR(64)即可 - 写入数据时,除了用随机IV加密原字段得到密文存入
myField外,额外对明文做加盐哈希处理,将哈希值存入myField_hash。哈希算法选择SHA-256即可,盐值为全局固定、存储在服务端配置的独立密钥,注意不要和加密用的密钥使用同一个值 - 查询时,
beforeFind钩子不需要加密查询条件,改为对查询的明文值做相同的加盐哈希,用myField_hash作为查询条件匹配即可 - 注意:该方案仅支持等值查询,不支持模糊查询、范围查询,如需后两类查询需要用到盲索引等更复杂的实现,成本会高很多;SHA-256算法的哈希冲突概率极低,常规业务场景下完全不需要考虑冲突问题
参考实现代码:
const crypto = require('crypto'); // 两个密钥分别存服务端环境变量,不要硬编码到代码或存入数据库 const HASH_SALT = process.env.FIELD_HASH_SALT; const ENCRYPT_KEY = Buffer.from(process.env.FIELD_ENCRYPT_KEY, 'hex'); // 计算字段哈希的公共方法 function calcFieldHash(plainText) { return crypto.createHmac('sha256', HASH_SALT).update(plainText).digest('hex'); } // beforeCreate/beforeUpdate钩子逻辑 myModel.addHook('beforeCreate', (instance) => { const plainValue = instance.myField; // 随机IV加密原字段,IV和密文拼接存储方便解密时取用 const iv = crypto.randomBytes(16); const cipher = crypto.createCipheriv('aes-256-cbc', ENCRYPT_KEY, iv); let encrypted = cipher.update(plainValue, 'utf8', 'hex'); encrypted += cipher.final('hex'); instance.myField = `${iv.toString('hex')}:${encrypted}`; // 存储哈希索引 instance.myField_hash = calcFieldHash(plainValue); }) // beforeFind钩子逻辑 myModel.addHook('beforeFind', (options) => { if (options.where?.myField) { const queryPlain = options.where.myField; // 替换为哈希字段查询 options.where.myField_hash = calcFieldHash(queryPlain); delete options.where.myField; } }) // afterFind等钩子解密逻辑需要先拆分IV和密文再解密 myModel.addHook('afterFind', (instance) => { if (!instance) return; const [ivHex, encrypted] = instance.myField.split(':'); const iv = Buffer.from(ivHex, 'hex'); const decipher = crypto.createDecipheriv('aes-256-cbc', ENCRYPT_KEY, iv); let plain = decipher.update(encrypted, 'hex', 'utf8'); plain += decipher.final('utf8'); instance.myField = plain; })
问题2:更优的数据库加密存储实现方案
可以根据业务安全要求选择对应方案:
- 如果仅需要防范数据库拖库导致的数据泄露,不需要对运维人员屏蔽明文数据,直接使用**MySQL自带的透明数据加密(TDE)**即可。该方案是数据库存储层加密,对业务代码完全无侵入,不需要修改任何Sequelize逻辑,支持所有类型的查询,性能损耗极低
- 如果需要字段级加密同时需要支持模糊、范围查询,可以选择专门的字段加密中间件方案,不过实现和运维成本会高很多
- 如果存储的字段敏感程度极高、不需要查询仅需存入后取用解密,直接使用你当前的随机IV加密方案即可,不需要额外加哈希索引,仅需要注意把IV和密文一起存储方便解密即可
内容的提问来源于stack exchange,提问作者db3000
相关产品推荐
相关产品推荐

