前言
有一個問題不知道大家想過沒?敏感字段數據是加密存儲在數據庫的表中,如果需要對這些敏感字段進行模模糊查詢,還用原來的通過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查詢,得到目標數據行的主鍵,再以目標數據行的主鍵為條件返回目標表進行精確查詢。
圖片一:分組組合加密前
圖片二:分組組合加密后
這種方法的優點就是原理簡單,實現起來也不復雜,但是有一定的局限性,算是一個對性能、業務相折中的一個方案,相比較之下,在能想的方法中,比較推薦這種方法,但是要特別注意的是,對模糊查詢的關鍵字的長度,要在業務層面進行限制;以手機號為例,可以要求對模糊查詢的關鍵字是四位或者是五位,具體可以再根據具體的場景進行詳細劃分。
為什么要增加這樣的限制呢?因為明文加密后長度為變長,有額外的存儲成本和查詢性能成本,分詞組合越多,需要的存儲空間以及所消耗的查詢性能成本也就更大,并且分詞越短,被硬破解的可能性也就越大,也會在一定程度上導致安全性降低;
環境配置
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
3、模糊查詢的時候,對模糊查詢關鍵字進行加密,以加密后的關鍵字密文為查詢條件,查詢密文映射表,得到目標數據行的id,再以目標數據行id為查詢條件,查詢目標數據表;
根據手機號碼的四位進行模糊查詢的時候,以加密后模糊查詢的關鍵字為條件,查詢sys_person_phone_encrypt表(人員的手機號碼分詞密文映射表),得到人員信息id;再以人員信息id,查詢人員信息表;
publicListgetPersonList(StringphoneVal){ if(phoneVal!=null){ returnthis.personDao.queryByPhoneEncrypt(this.encrypt(phoneVal)); } returnthis.personDao.queryList(phoneVal); }
圖片三:模糊查詢“6666”
審核編輯:劉清
-
存儲器
+關注
關注
38文章
7496瀏覽量
163932 -
SQL
+關注
關注
1文章
766瀏覽量
44164 -
AOP
+關注
關注
0文章
40瀏覽量
11103 -
加密解密算法
+關注
關注
0文章
7瀏覽量
1617
原文標題:加密后的敏感字段還能進行模糊查詢嗎?該如何實現?
文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論