跳至主要內容

密文模糊查询

大林鸱大约 4 分钟研发工具加密

在项目中,为了数据安全经常对一些敏感数据进行加密存储,例如用户真实姓名、身份证号码、详细地址、银行卡号、密码等。而我们不得不对加密后的数据进行查询,加密后的数据对模糊查询不友好,本文记录几种常用的方式。

方法一 先解密再查询

查询出目标表内所有的数据,在内存中对要模糊查询的敏感字段的加密数据进行解密,然后再遍历解密后的数据,与模糊查询关键字进行比较,筛选出包含有模糊查询关键字的数据行。

以下是某网友计算的数据量与内存损耗。

条数BytesMB
100w2400 万22.89
1000w2.4 亿228.89
1 亿24 亿2288.89

这种方式是有应用空间的,根据你的业务数据量,结合 Redis 能够很好的解决一些业务。

方法二 数据库解密算法

在数据库中实现与程序一致的加解密算法,修改模糊查询条件,使用数据库加解密函数先解密再模糊查找,这样做的优点是实现成本低,开发使用成本低,只需要将以往的模糊查找稍微修改一下就可以实现,但是缺点也很明显,这样做无法利用数据库的索引来优化查询,甚至有一些数据库可能无法保证与程序实现一致的加解密算法,但是对于常规的加解密算法都可以保证与应用程序一致。

例如:select * from sys_person where AES_DECRYPT(phone,'key') like '%0537'

如果对查询性能要求不是特别高、对数据安全性要求一般,可以使用常见的加解密算法比如说 AES、DES 之类的也是一个不错的选择。

如果公司有自己的算法实现,并且没有提供多端的算法实现,要么找个算法好的人去研究吃透补全多端实现,要么放弃使用这个办法。

这种方式不建议使用,原因是不建议使用数据库函数,它难以维护。

方法三 分词组合加密

新建一张分词密文映射表,在敏感字段数据新增、修改的后,对敏感字段进行固定长度分词组合,如12345678901的分词组合有123423453456等,再对每个分词进行加密,建立起敏感字段的分词密文与目标数据行主键的关联关系;在处理模糊查询的时候,对模糊查询关键字进行加密,用加密后的模糊查询关键字,对分词密文映射表进行 like 查询,得到目标数据行的主键,再以目标数据行的主键为条件返回目标表进行精确查询。

大家是否都对接过淘宝、拼多多、京东他们的 api,他们对平台订单数据中的用户敏感数据就是加密的同时支持模糊查询,使用就是这个方法,下面我整理了几家电商平台的密文字段检索方案的说明,感兴趣的可以查看下面链接。

  • 淘宝密文字段检索方案:
    https://open.taobao.com/docV3.htm?docId=106213&docType=1
  • 阿里巴巴文字段检索方案:
    https://jaq-doc.alibaba.com/docs/doc.htm?treeId=1&articleId=106213&docType=1
  • 拼多多密文字段检索方案:
    https://open.pinduoduo.com/application/document/browse?idStr=3407B605226E77F2
  • 京东密文字段检索方案:
    https://jos.jd.com/commondoc?listId=345

ps. 基本上都是一样的,果然都是互相抄袭,连加密后的数据格式都一致。

这种方法的优点就是原理简单,实现起来也不复杂,但是有一定的局限性,算是一个对性能、业务相折中的一个方案,相比较之下,在能想的方法中,比较推荐这种方法,但是要特别注意的是,对模糊查询的关键字的长度,要在业务层面进行限制;以手机号为例,可以要求对模糊查询的关键字是四位或者是五位,具体可以再根据具体的场景进行详细划分。

为什么要增加这样的限制呢?因为明文加密后长度为变长,有额外的存储成本和查询性能成本,分词组合越多,需要的存储空间以及所消耗的查询性能成本也就更大,并且分词越短,被硬破解的可能性也就越大,也会在一定程度上导致安全性降低。

总结

对于研发团队,推荐方法一和方法三,对于个人开发者,作者推荐方法二,因为它实现最简单、允许的查询条件够详细。并不是说越高大上的方法越好,适合你的项目的最好。

上次编辑于: