最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MyBatis實(shí)現(xiàn)字段加解密的實(shí)踐

 更新時(shí)間:2023年11月14日 10:40:27   作者:十年培訓(xùn)經(jīng)驗(yàn)的菜包  
為了數(shù)據(jù)安全問題,有時(shí)候需要將部分敏感字段加密后再入庫,本文主要介紹了MyBatis實(shí)現(xiàn)字段加解密的實(shí)踐,具有一定的參考價(jià)值,感興趣的可以了解一下

背景

互聯(lián)網(wǎng)系統(tǒng)充斥著各種敏感信息,包括各種個(gè)人信息、商業(yè)信息等等。按照要求,不允許隱私信息明文存儲(chǔ),需要進(jìn)行加密處理,防止造成隱私泄露的風(fēng)險(xiǎn)。
我司作為一個(gè)跨境電商公司,各系統(tǒng)中,自然免不了涉及各類敏感信息,并且對(duì)各類敏感信息的安全級(jí)別進(jìn)行了劃分,不同等級(jí)的加密要求級(jí)別有一定的差別。

方案

由于不同的敏感數(shù)據(jù)需要使用不同的加解密策略,在MySQL層面,無法滿足需求,所以只能在應(yīng)用代碼層面進(jìn)行實(shí)現(xiàn)。但需要考慮幾個(gè)點(diǎn)

  • 盡可能減少對(duì)業(yè)務(wù)代碼侵入性;
  • 以最小的風(fēng)險(xiǎn)進(jìn)行改動(dòng);
  • 方案可復(fù)用,方便拓展;

手動(dòng)加解密

這是首先被提出來的方案。該方案做法是

  • 在任何涉及到讀取敏感字段的業(yè)務(wù)代碼中,進(jìn)行手動(dòng)解密操作。
  • 在任何涉及到寫入敏感字段的業(yè)務(wù)代碼中,進(jìn)行手動(dòng)加密操作。

優(yōu)點(diǎn):

  • 暫無;

缺點(diǎn):

  • 侵入業(yè)務(wù)代碼,業(yè)務(wù)開發(fā)甚至需要關(guān)注不同級(jí)別的加解密策略;
  • 老舊系統(tǒng)調(diào)用復(fù)雜,可能出現(xiàn)重復(fù)加密或重復(fù)解密,導(dǎo)致無法復(fù)原原始數(shù)據(jù),風(fēng)險(xiǎn)數(shù)據(jù)非常高;
  • 若數(shù)據(jù)安全級(jí)別變動(dòng),加密策略升級(jí),所有可能涉及到的業(yè)務(wù)代碼都需要變更,風(fēng)險(xiǎn)半徑無法預(yù)測;

綜上所述,該方案完全無法滿足我們對(duì)方案的要求,屬于最笨的方案,可以直接say no。

自動(dòng)加解密

由于無法在MySQL層面實(shí)現(xiàn),又希望盡可能減少對(duì)業(yè)務(wù)代碼的侵入性,那么任務(wù)只能落在ORM框架或半ORM框架上。我們系統(tǒng)使用的是MyBatis,那么利用MyBatis的插件機(jī)制來實(shí)現(xiàn)自動(dòng)加解密,是個(gè)不錯(cuò)的選擇。

優(yōu)點(diǎn):

  • 業(yè)務(wù)代碼無需改造,幾乎對(duì)業(yè)務(wù)代碼無入侵性;
  • 加解密統(tǒng)一入口,風(fēng)險(xiǎn)可控;
  • 方案多個(gè)系統(tǒng)通用,加解密策略可隨時(shí)拓展;

缺點(diǎn):

  • 暫無;

實(shí)現(xiàn)

編碼

由于敏感數(shù)據(jù)被劃分成多個(gè)不同級(jí)別,各個(gè)級(jí)別使用的加解密算法不同,所以面對(duì)這種不同加密算法的場景,策略模式非常適合;

加解密策略

public interface SensitiveStrategy {

    /**
     * 加密
     */
    String encrypt(String value);

    /**
     * 解密
     */
    String decrypt(String value);
}

各種加解密算法,只要實(shí)現(xiàn)該接口即可,此處略。

自定義注解

自定義一個(gè)字段上的注解,目的是為了讓MyBatis攔截器識(shí)別哪些字段需要加解密,加解密的策略是什么。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
public @interface SensitiveField {

    Class<? extends SensitiveStrategy> sensitiveStrategy();
}

MyBatis攔截器

我們需要定義一個(gè)MyBatis攔截器,該攔截器的作用有以下:

  • 攔截入?yún)ⅲR(shí)別被@SensitiveField注解的字段,并使用指定加密策略,對(duì)字段內(nèi)容進(jìn)行加密;
  • 攔截查詢結(jié)果,識(shí)別被@SensitiveField注解的字段,并使用指定的解密策略,對(duì)字段內(nèi)容進(jìn)行解密;

我們知道,MyBatis的攔截器插件,可以對(duì)四大組件Executor、StatementHandler、ParameterHandler、ResultSetHandler進(jìn)行攔截,由于我們只需要對(duì)入?yún)⒑徒Y(jié)果進(jìn)行攔截和修改,所以只需指定攔截ParameterHandler、ResultSetHandler即可。

@Slf4j
@Component
@Intercepts(value = {
        @Signature(type = ParameterHandler.class,method = "setParameters",args = {PreparedStatement.class}),
        @Signature(type = ResultSetHandler.class,method = "handleResultSets",args = {Statement.class})
})
public class SensitiveInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {

        Object target = invocation.getTarget();
        //入?yún)⒓用?
        if (target instanceof ParameterHandler parameterHandler){
            //獲取參數(shù)對(duì)象
            Object parameterObj = ReflectUtil.getFieldValue(parameterHandler, "parameterObject");
            if (parameterObj != null){
                //獲取參數(shù)對(duì)象內(nèi)的字段
                Arrays.stream(ReflectUtil.getFields(parameterObj.getClass()))
                        .filter(field -> String.class.equals(field.getType()))
                        .filter(field -> field.getAnnotation(SensitiveField.class)!=null )
                        .filter(field -> ReflectUtil.getFieldValue(parameterObj,field) != null)
                        .forEach(field -> {
                            SensitiveField sensitiveField = field.getAnnotation(SensitiveField.class);
                            Class<? extends SensitiveStrategy> strategyClazz = sensitiveField.sensitiveStrategy();
                            if (strategyClazz != null){
                                SensitiveStrategy strategy = SpringContext.getBean(strategyClazz);
                                String encrypt = strategy.encrypt(ReflectUtil.getFieldValue(parameterObj, field).toString());
                                ReflectUtil.setFieldValue(parameterObj,field,encrypt);
                            }
                        });
                ReflectUtil.setFieldValue(parameterHandler,"parameterObject",parameterObj);
            }
        }

        Object resultObj = invocation.proceed();

        //出參解密
        if (resultObj != null && target instanceof ResultSetHandler){
            List<?> resultList = (List<?>) resultObj;
            for (Object result : resultList) {
                if (!SimpleTypeRegistry.isSimpleType(result.getClass())){
                    Arrays.stream(ReflectUtil.getFields(result.getClass()))
                            .filter(field -> String.class.equals(field.getType()))
                            .filter(field -> field.getAnnotation(SensitiveField.class)!=null )
                            .filter(field -> ReflectUtil.getFieldValue(result,field) != null)
                            .forEach(field -> {
                                SensitiveField sensitiveField = field.getAnnotation(SensitiveField.class);
                                Class<? extends SensitiveStrategy> strategyClazz = sensitiveField.sensitiveStrategy();
                                if (strategyClazz != null){
                                    SensitiveStrategy strategy = SpringContext.getBean(strategyClazz);
                                    String decrypt = strategy.decrypt(ReflectUtil.getFieldValue(result, field).toString());
                                    ReflectUtil.setFieldValue(result,field,decrypt);
                                }
                            });
                }
            }
            resultObj = resultList;
        }
        return resultObj;
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target,this);
    }
}

由于系統(tǒng)是基于SpringBoot的,所以我們將所有實(shí)現(xiàn)的加解密策略對(duì)象,交給Spring容器管理。在MyBatis攔截器中,直接從Spring容器中獲取對(duì)應(yīng)加解密策略使用接口。

上線

上線階段,我們分為以下幾個(gè)步驟實(shí)施

  • 臨時(shí)關(guān)閉敏感數(shù)據(jù)列的修改功能入口,避免出現(xiàn)備份后源數(shù)據(jù)變更;
  • 備份敏感字段列數(shù)據(jù),小表DBA直接備份,大表編寫代碼分批備份;
  • 利用apollo控制讀取時(shí)不解密,寫入時(shí)加密,對(duì)對(duì)應(yīng)字段進(jìn)行一次讀取后更新即可完成加密;
  • 觀察涉及的業(yè)務(wù)功能讀取是否正常;
  • 開啟敏感數(shù)據(jù)修改功能入口,觀察系統(tǒng)是否正常;

其他問題

其實(shí)在整個(gè)過程中,實(shí)現(xiàn)功能相關(guān)的編碼并不復(fù)雜。除此之外,需要去識(shí)別并解決其他的一些問題,這期間花費(fèi)了更多的時(shí)間,例如

敏感字段like搜索

字段加密后存儲(chǔ),就無法直接使用like關(guān)鍵字搜索。其實(shí)經(jīng)過我司安全部門評(píng)估,敏感字段也不允許進(jìn)行模糊搜索,有數(shù)據(jù)泄露風(fēng)險(xiǎn),所以在產(chǎn)品方案層面,直接砍掉了類似功能;
若是一定要保留改功能,也可以使用以下方案

  • 拓展一個(gè)新字段,用于模糊搜索,類型為text;
  • 對(duì)原始字符進(jìn)行分割,可按每N個(gè)字符為一項(xiàng)進(jìn)行分割,分割后每一項(xiàng)使用固定加密算法加密,再使用固定字符對(duì)每一項(xiàng)進(jìn)行拼接,形成新的字符串,保存到新字段;
  • like查詢時(shí),同樣也是分割、加密、拼接的方式;

注意,like字段需要使用text類型,性能會(huì)很低。

敏感字段group by

對(duì)于一些敏感級(jí)別較低的字段,采用了固定加密方式(即多次對(duì)相同的數(shù)據(jù)進(jìn)行加密后結(jié)果不變),此時(shí)由于結(jié)果不變,可以直接使用加密后的字段進(jìn)行g(shù)roup by;

但是對(duì)于敏感級(jí)別較高的字段,我司采用了動(dòng)態(tài)加密方式(即多次對(duì)相同的數(shù)據(jù)加密結(jié)果不一致),此時(shí)由于結(jié)果不一致,無法進(jìn)行g(shù)roup by操作。解決方案的拓展多一列,對(duì)源數(shù)據(jù)使用固定加密后,將結(jié)果存進(jìn)該拓展字段,group by業(yè)務(wù)使用。

到此這篇關(guān)于MyBatis實(shí)現(xiàn)字段加解密的實(shí)踐的文章就介紹到這了,更多相關(guān)MyBatis 字段加解密內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 如何使用JavaMail發(fā)送郵件

    如何使用JavaMail發(fā)送郵件

    這篇文章主要教大家如何使用JavaMail發(fā)送郵件在web應(yīng)用中,實(shí)現(xiàn)用戶注冊成功之后,將用戶的注冊信息以Email的形式發(fā)送到用戶的注冊郵箱當(dāng)中,感興趣的小伙伴們可以參考一下
    2015-12-12
  • Java 中HttpURLConnection附件上傳的實(shí)例詳解

    Java 中HttpURLConnection附件上傳的實(shí)例詳解

    這篇文章主要介紹了Java 中HttpURLConnection附件上傳的實(shí)例詳解的相關(guān)資料,希望通過本文大家能掌握這樣的知識(shí)內(nèi)容,需要的朋友可以參考下
    2017-09-09
  • Java?輕松掌握字符緩沖流的使用

    Java?輕松掌握字符緩沖流的使用

    這篇文章主要介紹了Java的字符緩沖流用法,字符緩沖流的用途很多,主要是幾個(gè)構(gòu)造方法的使用,在項(xiàng)目開發(fā)中經(jīng)常會(huì)用到,需要的朋友參考下吧
    2022-04-04
  • mall整合SpringSecurity及JWT實(shí)現(xiàn)認(rèn)證授權(quán)實(shí)戰(zhàn)

    mall整合SpringSecurity及JWT實(shí)現(xiàn)認(rèn)證授權(quán)實(shí)戰(zhàn)

    這篇文章主要為大家介紹了mall整合SpringSecurity及JWT實(shí)現(xiàn)認(rèn)證授權(quán)實(shí)戰(zhàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • 淺談Synchronized和Lock的區(qū)別

    淺談Synchronized和Lock的區(qū)別

    這篇文章主要介紹了淺談Synchronized和Lock的區(qū)別,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-10-10
  • 聊聊Java中是什么方法導(dǎo)致的線程阻塞

    聊聊Java中是什么方法導(dǎo)致的線程阻塞

    這篇文章主要介紹了聊聊Java中是什么方法導(dǎo)致的線程阻塞,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • 辨析Java中的String與StringBuffer及StringBuilder字符串類

    辨析Java中的String與StringBuffer及StringBuilder字符串類

    這里將為大家來辨析Java中的String與StringBuffer及StringBuilder字符串類型,通常來說StringBuilder的性能更加,需要的朋友可以參考下
    2016-05-05
  • SpringBoot中的@Configuration注解詳解

    SpringBoot中的@Configuration注解詳解

    這篇文章主要介紹了SpringBoot中的@Configuration注解詳解,Spring Boot推薦使用JAVA配置來完全代替XML 配置,JAVA配置就是通過 @Configuration和 @Bean兩個(gè)注解實(shí)現(xiàn)的,需要的朋友可以參考下
    2023-08-08
  • java 創(chuàng)建線程的幾種方式

    java 創(chuàng)建線程的幾種方式

    本文主要介紹了java中創(chuàng)建線程的幾種方式。具有很好的參考價(jià)值,下面跟著小編一起來看下吧
    2017-02-02
  • 簡單解析java方法在調(diào)用在內(nèi)存中的執(zhí)行過程

    簡單解析java方法在調(diào)用在內(nèi)存中的執(zhí)行過程

    這篇文章主要介紹了簡單解析java方法在調(diào)用在內(nèi)存中的執(zhí)行過程,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-07-07

最新評(píng)論

迭部县| 松滋市| 巴彦淖尔市| 从化市| 岗巴县| 琼中| 馆陶县| 上蔡县| 田阳县| 石渠县| 泽普县| 太保市| 西昌市| 陆丰市| 纳雍县| 临武县| 台前县| 来安县| 河曲县| 丹寨县| 南丹县| 福安市| 密云县| 保亭| 漯河市| 克什克腾旗| 宁夏| 富阳市| 两当县| 长海县| 镇坪县| 黎川县| 定结县| 辽宁省| 临沭县| 万源市| 古田县| 南充市| 新乐市| 光泽县| 平果县|