Skip to content

面试速答(先看这里)

**一句话结论:**数据库加密可以保障数据的安全,但是也会带来很多的问题,其中有一个比较关键的就是数据的模糊查询的问题。

60秒标准回答:

数据库加密可以保障数据的安全,但是也会带来很多的问题,其中有一个比较关键的就是数据的模糊查询的问题

当我们通过加密后把密文存到数据库中的时候,在通过明文进行模糊查询是不生效的

比如 Hollis 加密后的内容是 363164846D8200899E314897E64A7420 ,那么当我想用 Ho 来做模糊查询时候,那么他的密文是 71AAFD38484F3160708C6A6D2D5F736B ,这两个密文可以说是没有任何关系的,所以,是无法直接做模糊查询的。那么如何解决这个问题呢?

**答题顺序:**结论 → 原理/机制 → 关键流程 → 场景与取舍 → 易错点

回答主线:

  • **要点1:**当我们通过加密后把密文存到数据库中的时候,在通过明文进行模糊查询是不生效的。
  • **要点2:**比如 Hollis 加密后的内容是 363164846D8200899E314897E64A7420 ,那么当我想用 Ho 来做模糊查询时候,那么他的密文是 71AAFD38484F3160708C6A6D2D5F736B ,这两个密文可以说是没有任何关系的,所以,是无法直接做模糊查询的。
  • **要点3:**这个方案的优点就是实现简单,缺点也很明显,需要把所有数据都加载到内存中,容易导致OOM。
  • **要点4:**这样也就能实现一个模糊查询的效果了,但是这个方案有个缺点,就是无法用到索引,不是因为用like,而是因为我们在字段上用了函数,索引就会失效。
  • **要点5:**这个方案的缺点也比较明显,第一个就是需要冗余很多字段,第二个就是不够灵活,如果我按照 Holli 来查询的话就不支持了。

**记忆锚点:**Hollis → https → Holl → llis → D8200899E314897E64A7420 → openpinduoduocom

易错提醒:

  • 这个方案的优点就是实现简单,缺点也很明显,需要把所有数据都加载到内存中,容易导致OOM。

加分表达:

  • 数据库加密可以保障数据的安全,但是也会带来很多的问题,其中有一个比较关键的就是数据的模糊查询的问题。
  • 不推荐 加密的时候如果用了函数的话,解密的时候我们也可以借助函数来做解密,同时做模糊查询,比如加密时使用了AES_ENCRYPT算法: 那么在做模糊查询的时候就可以这样做: 这样也就能实现一个模糊查询的效果了,但是这个方案有个缺点,就是无法用到索引,不是因为用like,而是因为我们在字段上用了函数,索引就会失效。
  • 这个方案的缺点也比较明显,第一个就是需要冗余很多字段,第二个就是不够灵活,如果我按照 Holli 来查询的话就不支持了。

追问准备:

  • 围绕「Hollis」:底层原理是什么?使用时有哪些边界和常见坑?
  • 围绕「https」:底层原理是什么?使用时有哪些边界和常见坑?
  • 围绕「Holl」:底层原理是什么?使用时有哪些边界和常见坑?
  • 如果线上出现异常,你会如何定位、验证并规避?

典型回答 ​

📄 ✅数据库怎么做加密和解密?

打开文档:✅数据库怎么做加密和解密?

数据库加密可以保障数据的安全,但是也会带来很多的问题,其中有一个比较关键的就是数据的模糊查询的问题。

当我们通过加密后把密文存到数据库中的时候,在通过明文进行模糊查询是不生效的。

比如Hollis加密后的内容是363164846D8200899E314897E64A7420,那么当我想用Ho来做模糊查询时候,那么他的密文是71AAFD38484F3160708C6A6D2D5F736B,这两个密文可以说是没有任何关系的,所以,是无法直接做模糊查询的。那么如何解决这个问题呢?

先解密再查询 ​

一种比较常见的方法,就是把要查询的表中的所有符合条件的数据,都加载到应用内存中,在内存中逐个解密,然后再做模糊匹配。

这个方案的优点就是实现简单,缺点也很明显,需要把所有数据都加载到内存中,容易导致OOM。不推荐

明文映射表 ​

还有人提出过说单独建一张表,其中保存明文和目标表之间的映射,需要模糊查询的时候先去明文映射表中查到主键,然后再去目标表查询数据。

但是这个方案基本上是属于自欺欺人,因为一旦数据被拖库,还是会丢。不推荐

数据库解密函数 ​

加密的时候如果用了函数的话,解密的时候我们也可以借助函数来做解密,同时做模糊查询,比如加密时使用了AES_ENCRYPT算法:

yaml
-- 加密数据
INSERT INTO user_data (username, credit_card) VALUES ('Hollis', AES_ENCRYPT('1234-5678-9012-3456', 'hollis_secret_key'));

那么在做模糊查询的时候就可以这样做:

yaml
SELECT * FROM user_data WHERE AES_DECRYPT(credit_card, 'hollis_secret_key') like 'Hol%';

这样也就能实现一个模糊查询的效果了,但是这个方案有个缺点,就是无法用到索引,不是因为用like,而是因为我们在字段上用了函数,索引就会失效。

这个方案适合于表中数据量不大,或者查询条件中还有其他查询字段可以走索引的情况。

明文分词 ​

首先有一个比较简单的做法,那就是对明文进行分词,然后分别加密后存储到数据库中,比如Hollis这个需要加密的字符串,我们就可以把他拆成Ho 、Holl、llis等这几个字符串,然后分别对他们进行加密,并保存到数据库中。

这样当我们使用Ho 、Holl、llis 进行查询的时候,就可以对明文加密后去数据库中匹配了。

这个方案的缺点也比较明显,第一个就是需要冗余很多字段,第二个就是不够灵活,如果我按照Holli来查询的话就不支持了。

当然,也有一些改进的方式,比如并不需要增加多个字段,可以把这些需要用于模糊查询的信息都放到同一个字段中,如DECRYPT_NAME,拼接成一个字符串就行了。如71AAFD38484F3160708C6A6D2D5F736B,83B01A578395CE81AEAAC6A4FE70AA94,E90048FB068AA98B7EC751CBD6DC78B7 这样就只需要通过这个字段做模糊查询就行了(索引也会失效)。SQL如下:

yaml
SELECT *
FROM hollis_test_table
WHERE DECRYPT_NAME REGEXP '71AAFD38484F3160708C6A6D2D5F736B|83B01A578395CE81AEAAC6A4FE70AA94|E90048FB068AA98B7EC751CBD6DC78B7';

很多公司其实都是用的这种方案,比如:

淘宝:https://open.taobao.com/docV3.htm?docId=106213&docType=1

拼多多:https://open.pinduoduo.com/application/document/browse?idStr=7553D76C8D1713EF