0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

加密后的敏感字段还能进行模糊查询吗?该如何实现?

jf_ro2CN3Fa 来源:CSDN 2023-06-05 16:43 次阅读

前言

有一个问题不知道大家想过没?敏感字段数据是加密存储在数据库的表中,如果需要对这些敏感字段进行模模糊查询,还用原来的通过sql的where从句的like来模糊查询的方式肯定是不行的,那么应该怎么实现呢?这篇文章就来解决这个问题。

场景分析

假如有类似这样的一个场景:有一个人员管理的功能,人员信息列表的主要字段有姓名、性别、用户账号、手机号码、身份证号码、家庭住址、注册日期等,可以对任意一条数据进行增、删、改、查,其中姓名、身份证号码、手机号码字段要支持模糊查询。

简单分析一个场景,可以知道:手机号码、身份证号码、家庭人址字段数据是敏感数据,这些字段的数据是要加密存储在数据库里,在页面上展示的时候需要进行脱敏处理的。

如果用户想要查询真实姓名是包含有“张三”的所有人员信息,可以在页面上输入一个关键字,如“张三”,点击开始查询后,这个参数会传递到后台,后台会执行一条sql,如“select * from sys_person where real_name like ‘%张三%’”,执行结果中包含了所有用户真实姓名包含有“张三”的所有数据记录,如“张三”,“张三丰”等。

如果用户要查询手机号码尾号是“0537”的用户,后台执行类似与姓名模糊查询的sql,"select * from sys_person where phone like '%0537'",肯定是得不到正确的结果的,因为手机号码字段在数据库中的数据是加密后的结果,而‘0537’是明文。身份证号码、家庭住址等其他敏感字段在模糊查询的时候也都有类似这样的问题,这也是敏感字段模糊查询的痛点,即模糊查询关键字与实际存储的数据不一致。

实现方案

下面分享几种解决方案:

第一种,先解密再查询

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

这种方法是最容易想到的,但有一个比较明显的问题是,模糊查询的过程是在内存中进行的,如果数据量特别大,很容易导致内存溢出,因此不推荐在生产中使用这种方法;

第二种,明文映射表

新建一张映射表,存储敏感字段解密后的数据与目标表主键的映射表,需要模糊查询的时候,先对明文映射表进行模糊查询,得到符合条件的目标数据的主键,再返回来根据主键查询目标表;

这种方法,实际上是有点掩耳盗铃的感觉,敏感字段加密存储的字段主要是考虑到安全性,使用明文映射表来存储解密后的敏感字段,实际上相当于敏感字段没有加密存储,与最被要对敏感字段加密的初衷相违背,因此不推荐在生产中使用这种方法;

第三种,数据库层面进行解密查询

后台在执行查询sql时对敏感字段先解密,然后再执行like,以上面的人员管理列表模糊查询为例,即对sql的改造为:“select * from sys_person where AES_DECRYPT(phone,'key') like '%0537'”;

这种方法的优点是,成本比较小,容易实现,但是缺点很明显,该字段无法通过数据库索引来优化查询,另外有一些数据库无法保证数据库的加解密算法与程序的加解密算法一致,可能会导致可以程序中加密,但是无法在数据库中解密的或者可以在数据库加密无法在程序中解密的问题,因此不推荐在生产中使用这种方法;

第四种,分词密文映射表

这种方法是对第二种思路的基础上进行延伸优化,也是主流的方法。新建一张分词密文映射表,在敏感字段数据新增、修改的后,对敏感字段进行分词组合,如“15503770537”的分词组合有“155”、“0377”、“0537”等,再对每个分词进行加密,建立起敏感字段的分词密文与目标数据行主键的关联关系;在处理模糊查询的时候,对模糊查询关键字进行加密,用加密后的模糊查询关键字,对分词密文映射表进行like查询,得到目标数据行的主键,再以目标数据行的主键为条件返回目标表进行精确查询。

cc9384c0-037b-11ee-90ce-dac502259ad0.png

图片一:分组组合加密前

ccc196f8-037b-11ee-90ce-dac502259ad0.png

图片二:分组组合加密后

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

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

环境配置

jdk版本:1.8开发工具:Intellij iDEA 2020.1

springboot:2.3.9.RELEASE

mybatis-spring-boot-starter:2.1.4

依赖配置

示例主要用到了SpringAop,加密是对称加密,用到了hutool工具包里的加密解密工具类,也可以使用自己封装的加密解密工具类。


org.springframework.boot
spring-boot-starter-aop


cn.hutool
hutool-all
5.3.3

代码实现

1、新建分词密文映射表;

如果是多个模糊查询的字段,可以共用在一张分词密文映射表中扩展多个字段,以示例中的人员管理功能为例,新建sys_person_phone_encrypt表(人员的手机号码分词密文映射表),用于存储人员id与分词组合密文的映射关系

createtableifnotexistssys_person_phone_encrypt
(
idbigintauto_incrementcomment'主键'primarykey,
person_idintnotnullcomment'关联人员信息表主键',
phone_keyvarchar(500)notnullcomment'手机号码分词密文'
)
comment'人员的手机号码分词密文映射表';

2、敏感字段数据在保存入库的时候,对敏感字段进行分词组合并加密码,存储在分词密文映射表;

在注册人员信息的时候,先取出通过AOP进行加密过的手机号码进行解密;手机号码解密之后,对手机号码按照连续四位进行分词组合,并对每一个手机号码的分词进行加密,最后把所有的加密后手机号码分词拼接成一个字符串,与人员id一起保存到人员的手机号码分词密文映射表;

publicPersonregiste(Personperson){
this.personDao.insert(person);
Stringphone=this.decrypt(person.getPhoneNumber());
StringphoneKeywords=this.phoneKeywords(phone);
this.personDao.insertPhoneKeyworkds(person.getId(),phoneKeywords);
returnperson;
}
privateStringphoneKeywords(Stringphone){
Stringkeywords=this.keywords(phone,4);
System.out.println(keywords.length());
returnkeywords;
}

//分词组合加密
privateStringkeywords(Stringword,intlen){
StringBuildersb=newStringBuilder();
for(inti=0;i< word.length(); i++) {
        int start = i;
        int end = i + len;
        String sub1 = word.substring(start, end);
        sb.append(this.encrypt(sub1));
        if (end == word.length()) {
            break;
        }
    }
    return sb.toString();
}
public String encrypt(String val) {
    //这里特别注意一下,对称加密是根据密钥进行加密和解密的,加密和解密的密钥是相同的,一旦泄漏,就无秘密可言,
    //“fanfu-csdn”就是我自定义的密钥,这里仅作演示使用,实际业务中,这个密钥要以安全的方式存储;
    byte[] key = SecureUtil.generateKey(SymmetricAlgorithm.DES.getValue(), "fanfu-csdn".getBytes()).getEncoded();
    SymmetricCrypto aes = new SymmetricCrypto(SymmetricAlgorithm.DES, key);
    String encryptValue = aes.encryptBase64(val);
    return encryptValue;
}
public String decrypt(String val) {
    //这里特别注意一下,对称加密是根据密钥进行加密和解密的,加密和解密的密钥是相同的,一旦泄漏,就无秘密可言,
    //“fanfu-csdn”就是我自定义的密钥,这里仅作演示使用,实际业务中,这个密钥要以安全的方式存储;
    byte[] key = SecureUtil.generateKey(SymmetricAlgorithm.DES.getValue(), "fanfu-csdn".getBytes()).getEncoded();
    SymmetricCrypto aes = new SymmetricCrypto(SymmetricAlgorithm.DES, key);
    String encryptValue = aes.decryptStr(val);
    return encryptValue;
}

3、模糊查询的时候,对模糊查询关键字进行加密,以加密后的关键字密文为查询条件,查询密文映射表,得到目标数据行的id,再以目标数据行id为查询条件,查询目标数据表;

根据手机号码的四位进行模糊查询的时候,以加密后模糊查询的关键字为条件,查询sys_person_phone_encrypt表(人员的手机号码分词密文映射表),得到人员信息id;再以人员信息id,查询人员信息表;

publicListgetPersonList(StringphoneVal){
if(phoneVal!=null){
returnthis.personDao.queryByPhoneEncrypt(this.encrypt(phoneVal));
}
returnthis.personDao.queryList(phoneVal);
}

select*fromsys_personwhereidin
(selectperson_idfromsys_person_phone_encrypt
wherephone_keylikeconcat('%',#{phoneVal},'%'))

cd085a98-037b-11ee-90ce-dac502259ad0.png

图片三:模糊查询“6666”





审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 存储器
    +关注

    关注

    38

    文章

    7484

    浏览量

    163769
  • SQL
    SQL
    +关注

    关注

    1

    文章

    762

    浏览量

    44117
  • AOP
    AOP
    +关注

    关注

    0

    文章

    40

    浏览量

    11099
  • 加密解密算法

    关注

    0

    文章

    7

    浏览量

    1612

原文标题:加密后的敏感字段还能进行模糊查询吗?该如何实现?

文章出处:【微信号:芋道源码,微信公众号:芋道源码】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    有什么方法能使连接外部看门狗还能进行程序的升级?

    单片机连接外部硬件看门狗,程序下载不了,拆除硬件看门狗,程序就可以下载了。应该是程序下载过程中外狗一直复位单片机,导致程序下载不了。有什么方法能使连接外部看门狗还能进行程序的升级
    发表于 09-16 13:48

    加密版C6748不能进行io置位吗?

    接口。那么可不可以像非加密版的6748通过sfh_OMAP-L138工具进行串口烧写(经验证sfh_OMAP-L138工具不能用于加密版芯片)?实现串口烧写是否需要开发二次boot来支
    发表于 10-14 16:49

    FPGA通过串口得到数据 得到数据进行加密 无法得到加密结果的信号

    1.可以实现串口的回环通信 2.串口接受完信号发送一个信号给加密模块进行加密 无法得到
    发表于 04-01 20:49

    注塑机被水淹应该怎么处理?还能进行维修吗?

    注塑机被水淹应该怎么处理?还能进行维修吗?
    发表于 11-12 07:43

    怎样去实现Stm32在启用IWDG看门狗还能进行休眠呢

    怎样去实现Stm32在启用IWDG看门狗还能进行休眠呢?有哪些方法?
    发表于 01-17 06:04

    基于动态查询表的模糊控制策略及其应用

    研究基于动态查询表的模糊控制策略及其在转臂式倒立摆中的应用Z 采用一种新的倒立摆系统的控制方法, 将传感器检测的倒立摆的两个角度信息传送到控制器, 控制器利用信息的
    发表于 07-15 09:01 22次下载

    Delphi教程之标准/模糊查询

    Delphi教程之标准/模糊查询,学习Delphi的必备资料。
    发表于 03-31 11:29 2次下载

    MySQL 教程—联合查询

    联合查询:union,将多次查询(多条select语句)的结果,在字段数相同的情况下,在记录的层次上进行拼接。
    发表于 09-11 12:56 5次下载
    MySQL 教程—联合<b class='flag-5'>查询</b>

    面向云数据库的属性基加密查询转换中间件

    针对云数据库租户隐私数据的加密查询问题,提出并实现了一种面向云数据库的属性基加密( ABE)和查询转换服务中间件。首先,服务中间件的加解密
    发表于 01-15 14:45 5次下载
    面向云数据库的属性基<b class='flag-5'>加密</b>和<b class='flag-5'>查询</b>转换中间件

    MongoDB引入字段级数据库加密安全功能

    MongoDB 引入了一个全新的安全功能:字段级数据库加密。在有了静态存储加密和传输加密之后,为什么还要字段
    的头像 发表于 04-02 17:56 2849次阅读
    MongoDB引入<b class='flag-5'>字段</b>级数据库<b class='flag-5'>加密</b>安全功能

    Oracle:查看所有表和字段、表注释、字段注释的步骤

    小伙伴们按照我写的文章顺利安装好Oracle数据库,又在微信上问我:我想查看Oracle数据库中所有表和字段以及表注释和字段的注释,我怎么操作呢?看着小伙伴们这么高的学习热情,这些
    发表于 08-10 16:21 3995次阅读
    Oracle:查看所有表和<b class='flag-5'>字段</b>、表注释、<b class='flag-5'>字段</b>注释的步骤

    一种基于星座模糊的物理层加密方案

    为在物理层中进行信息安全传输,提出一种基于星座模糊的物理层加密方案。将信道系数作为密钥,采用信道系数与已调符号矢量叠加的方式实现加密。考虑信
    发表于 04-02 11:13 4次下载
    一种基于星座<b class='flag-5'>模糊</b>的物理层<b class='flag-5'>加密</b>方案

    如何对加密的数据进行模糊查询

    我们先来看看第一个做法,将所有数据加载到内存中进行解密,这个如果数据量小的话可以使用这个方式来做,这样做既简单又实惠,如果数据量大的话那就是灾难,我们来大致算一下。
    的头像 发表于 08-16 10:14 1541次阅读

    Redis的分页+多条件模糊查询组合实现方案

    Redis是key-value类型的内存数据库,通过key直接取数据虽然很方便,但是并未提供像mysql那样方便的sql条件查询支持。因此我们需要借助Redis提供的结构和功能去自己实现模糊条件
    的头像 发表于 11-20 14:26 918次阅读
    Redis的分页+多条件<b class='flag-5'>模糊</b><b class='flag-5'>查询</b>组合<b class='flag-5'>实现</b>方案

    oracle更新clob字段脚本写法

    ; BEGIN -- 先查询要更新的CLOB字段的内容 SELECT clob_column INTO clob_var FROM your_table WHERE id = 1 ; -- 修改
    的头像 发表于 11-21 11:28 3201次阅读