一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

云服務(wù)器|WEB服務(wù)器|FTP服務(wù)器|郵件服務(wù)器|虛擬主機(jī)|服務(wù)器安全|DNS服務(wù)器|服務(wù)器知識|Nginx|IIS|Tomcat|

服務(wù)器之家 - 服務(wù)器技術(shù) - 服務(wù)器知識 - 保護(hù)敏感數(shù)據(jù):Spring Boot中敏感字段加密解密的高效解決方案

保護(hù)敏感數(shù)據(jù):Spring Boot中敏感字段加密解密的高效解決方案

2024-01-02 08:38未知服務(wù)器之家 服務(wù)器知識

前言 相信大家都有這樣一個煩惱,就是經(jīng)常會接到各種推銷、廣告的電話和短信,如果你沒有在他那里留下過聯(lián)系方式,他又是如何得到了你的聯(lián)系方式呢?毫無疑問,是個人信息被泄漏了。個人信息的泄漏有人為不合法謀利的因

前言

相信大家都有這樣一個煩惱,就是經(jīng)常會接到各種推銷、廣告的電話和短信,如果你沒有在他那里留下過聯(lián)系方式,他又是如何得到了你的聯(lián)系方式呢?毫無疑問,是個人信息被泄漏了。個人信息的泄漏有人為不合法謀利的因素,也有系統(tǒng)不合理的安全設(shè)計造成泄漏的因素。當(dāng)然系統(tǒng)設(shè)計的角度出發(fā),敏感信息需要加密存儲的,數(shù)據(jù)展示的時候也要進(jìn)行相應(yīng)的脫敏處理,但是從一些關(guān)于個信息泄漏的新聞報道來看,有好多的網(wǎng)站后臺竟然是“裸奔”狀態(tài),簡直太可怕了。其實敏感數(shù)據(jù)的處理也不復(fù)雜,說到底是安全意識不強(qiáng)。當(dāng)然,這篇文章和大家分享的重點是加密和解密的方法,不是數(shù)據(jù)安全的重要性。

基本概念

敏感數(shù)據(jù)

敏感數(shù)據(jù)是指那些泄漏后可能會給社會或個人造成嚴(yán)重危害的數(shù)據(jù),以個人隱私信息為例,如手機(jī)號碼、家庭住址、郵箱、身份證號、銀行卡帳號、購物網(wǎng)站的支付密碼、登陸密碼等等。另外從社會的角度出發(fā),也有很多數(shù)據(jù)是屬于敏感數(shù)據(jù),如:居民的生物基因信息等等。

數(shù)據(jù)加密

數(shù)據(jù)加密是指對數(shù)據(jù)重新編碼來保護(hù)數(shù)據(jù),獲取實際數(shù)據(jù)的唯一辦法就是使用密鑰解密數(shù)據(jù);

數(shù)據(jù)解密

數(shù)據(jù)解密與數(shù)據(jù)加密是相對的,即使用密鑰對加密的數(shù)據(jù)進(jìn)行解密的過程;

加密方式

加密的方式,一般是兩種:對稱加密和非對稱加密;

對稱加密只有一個秘鑰,加密和解密都是用同一個秘鑰,如AES、DES等;

非對稱加密有兩個秘鑰,一個是公鑰,一個是私鑰。使用公鑰對數(shù)據(jù)進(jìn)行加密,加密后的數(shù)據(jù)只有私鑰可以解密,一般公鑰是公開的,私鑰是不公開的;如RSA、DSA等;

實現(xiàn)原理

Springboot項目中,客戶端通過接口向服務(wù)端讀取或?qū)懭朊舾袛?shù)據(jù)時,常會有這樣的業(yè)務(wù)需求:

1、在客戶端向服務(wù)器端發(fā)起寫入請求,服務(wù)端需要對寫入的敏感數(shù)據(jù)進(jìn)行加密后存儲;

2、在客戶端從服務(wù)器端向外讀取數(shù)據(jù)的時候,需要對輸出的敏感數(shù)據(jù)進(jìn)行解密;

顯然這種場景,對于加密的方式的選擇,對稱加密是最好的選擇;那么如何實現(xiàn)對寫入請求、讀取請求的敏感數(shù)據(jù)的加密、解密處理呢?解決方案如下:

1、自定義兩個切面注解,分別是加密切面注解、解密切面注解,作用于需要加密或解密的敏感數(shù)據(jù)處理的業(yè)務(wù)處理類的具體業(yè)務(wù)處理方法上;

2、自定義兩個敏感字段處理注解,分別是加密字段注解、解密字段注解,作用于需要輸入或輸出的對象的敏感字段上;如果輸入對象上標(biāo)記了加密字段注解,則表示該字段在對內(nèi)寫入數(shù)據(jù)庫的時候,需要加密處理;同理,如果輸出對象上標(biāo)記了解密字段注解,則表示該字段在對外輸出的時候,需要進(jìn)行解密;

3、使用面向切面編程,定義兩個切面類,分別是加密切面類和解密切面類,選擇Spring AOP的環(huán)繞通知來具體實現(xiàn);加密切面類中,以注解的方式定義切入點,用到的注解就是自定義的加密切面注解;

4、如果新增、編輯等寫入類的業(yè)務(wù)請求處理方法上標(biāo)記了加密切面注解,那么寫入請求在正式被業(yè)務(wù)處理方法處理前,會命中加密切面類,加密切面類的環(huán)繞通知方法被觸發(fā),然后根據(jù)輸入的參數(shù)對象中的字段是否標(biāo)記了自定義的加密字段注解,來決定是否對當(dāng)前字段進(jìn)行加密處理;

5、同理,如果是查詢等讀取類的業(yè)務(wù)請求處理方法上標(biāo)記了解密切面注解,那么讀取請求被業(yè)務(wù)處理類處理完之后,會命中解密切面類,解密切面類的環(huán)繞通知方法被觸發(fā),然后根據(jù)返回對象的字段是否標(biāo)記了解密字段注解,來決定是否對當(dāng)前字段進(jìn)行解密處理。

保護(hù)敏感數(shù)據(jù):Spring Boot中敏感字段加密解密的高效解決方案

實現(xiàn)方案

環(huán)境配置

jdk版本:1.8開發(fā)工具:Intellij iDEA 2020.1

springboot:2.3.9.RELEASE

mybatis-spring-boot-starter:2.1.4

依賴配置

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.3.3</version>
</dependency>

示例時序圖

保護(hù)敏感數(shù)據(jù):Spring Boot中敏感字段加密解密的高效解決方案圖片

示例代碼

1、自定義四個注解:@DecryptField(解密字段注解)、@EncryptField(加密字段注解)、@NeedEncrypt(解密切面注解)、@NeedEncrypt(加密切面注解),其中@DecryptField作用于需要解密的字段上;@EncryptField作用于需要加密的字段上;@NeedEncrypt作用于需要對入?yún)?shù)進(jìn)行加密處理的方法上;@NeedDecrypt作用于需要對返回值進(jìn)行解密處理的方法上;

//解密字段注解
@Target(value = {ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DecryptField {
}
//加密字段注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface EncryptField {
}
//作用于對返回值進(jìn)行解密處理的方法上
@Target(value = {ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface NeedDecrypt {
}
//作用于需要對入?yún)?shù)進(jìn)行加密處理的方法上
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NeedEncrypt {
}

2、把自定義的加密字段注解、解密字段注解標(biāo)記在需要加密或者解密的字段上;這里表示在寫入人員的手機(jī)號碼、身份證號碼、家庭住址門牌號碼時,要進(jìn)行加密處理;在讀取人員的手機(jī)號碼、身份證號碼、家庭住址門牌號碼時,要進(jìn)行解密處理;

@Slf4j
@Data
public class Person  {
 private Integer id;
 private String userName;
 private String loginNo;
 @EncryptField
 @DecryptField
 private String phoneNumber;
 private String sex;
 @DecryptField
 @EncryptField
 private String IDCard;
 private String address;
 @EncryptField
 @DecryptField
 private String houseNumber;
}

3、把@NeedEncrypt和@NeedDecrypt標(biāo)記在需要對入?yún)?shù)、返回值中的敏感字段進(jìn)行加密、解密處理的業(yè)務(wù)處理方法上;

@RestController
@RequestMapping("/person")
@Slf4j
public class PersonController {
    @Autowired
    private IPersonService personService;
    //添加人員信息
    @PostMapping("/add")
    @NeedEncrypt
    public Person add(@RequestBody Person person, Model model) {
        Person result = this.personService.registe(person);
        log.info("http://增加person執(zhí)行完成");
        return result;
    }
    //人員信息列表查詢
    @GetMapping("/list")
    @NeedDecrypt
    public List<Person> getPerson() {
        List<Person> persons = this.personService.getPersonList();
        log.info("http://查詢person列表執(zhí)行完成");
        return persons;
    }
    //人員信息詳情查詢
    @GetMapping("/{id}")
    @NeedDecrypt
    public Person get(@PathVariable Integer id) {
        Person persnotallow= this.personService.get(id);
        log.info("http://查詢person詳情執(zhí)行完成");
        return person;
    }
}

4、自定義加密切面類(EncryptAop)和解密切面類(DecryptAop):用@NeedEncrypt注解定義加密切點,在加密切點的環(huán)繞通知方法里執(zhí)行到具體的業(yè)務(wù)處理方法之前,判斷輸入對象的參數(shù)字段是否標(biāo)記了@EncryptField(加密字段注解),如果判斷結(jié)果為true,則使用java反射對該字段進(jìn)行加密處理,注意這里引用了hutool的工具包,使用了工具包里的加密和解密方法,這里也可以替換成其他的方式;用@NeedDecrypt注解定義解密切點,在解密切點的環(huán)繞通知方法里執(zhí)行完具體的業(yè)務(wù)處理方法之后,判斷輸出對象的參數(shù)字段是否標(biāo)記了@DecryptField(解密字段注解),如果判斷結(jié)果為true,則使用java反射對該 字段進(jìn)行解密處理;

@Component
@Aspect
@Slf4j
public class EncryptAop {
    /**
     * 定義加密切入點
     */
    @Pointcut(value = "@annotation(com.fanfu.anno.NeedEncrypt)")
    public void pointcut() {
    }


    /**
     * 命中加密切入點的環(huán)繞通知
     *
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable
     */
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        log.info("http://環(huán)繞通知 start");
        //獲取命中目標(biāo)方法的入?yún)?shù)
        Object[] args = proceedingJoinPoint.getArgs();
        if (args.length > 0) {
            for (Object arg : args) {
                //按參數(shù)的類型進(jìn)行判斷,如果業(yè)務(wù)中還有其他的類型,可酌情增加
                if (arg != null) {
                    if (arg instanceof List) {
                        for (Object tmp : ((List) arg)) {
                            //加密處理
                            this.deepProcess(tmp);
                        }
                    } else {
                        this.deepProcess(arg);
                    }
                }
            }
        }
        //對敏感數(shù)據(jù)加密后執(zhí)行目標(biāo)方法
        Object result = proceedingJoinPoint.proceed();
        log.info("http://環(huán)繞通知 end");
        return result;
    }


    public void deepProcess(Object obj) throws IllegalAccessException {
        if (obj != null) {
            //獲取對象的所有字段屬性并遍歷
            Field[] declaredFields = obj.getClass().getDeclaredFields();
            for (Field declaredField : declaredFields) {
                //判斷字段屬性上是否標(biāo)記了@EncryptField注解
                if (declaredField.isAnnotationPresent(EncryptField.class)) {
                    //如果判斷結(jié)果為真,則取出字段屬性值,進(jìn)行加密、重新賦值
                    declaredField.setAccessible(true);
                    Object valObj = declaredField.get(obj);
                    if (valObj != null) {
                        String value = valObj.toString();
                        //開始敏感字段屬性值加密
                        String decrypt = this.encrypt(value);
                        //把加密后的字段屬性值重新賦值
                        declaredField.set(obj, decrypt);
                    }
                }
            }
        }
    }


    private String encrypt(String value) {
        //這里特別注意一下,對稱加密是根據(jù)密鑰進(jìn)行加密和解密的,加密和解密的密鑰是相同的,一旦泄漏,就無秘密可言,
        //“fanfu-csdn”就是我自定義的密鑰,這里僅作演示使用,實際業(yè)務(wù)中,這個密鑰要以安全的方式存儲;
        byte[] key = SecureUtil.generateKey(SymmetricAlgorithm.DES.getValue(), "fanfu-csdn".getBytes()).getEncoded();
        SymmetricCrypto aes = new SymmetricCrypto(SymmetricAlgorithm.DES, key);
        String encryptValue = aes.encryptBase64(value);
        return encryptValue;
    }


}
@Component
@Aspect
@Slf4j
public class DecryptAop {
    /**
     * 定義需要解密的切入點
     */
    @Pointcut(value = "@annotation(com.fanfu.anno.NeedDecrypt)")
    public void pointcut() {
    }


    /**
     * 命中的切入點時的環(huán)繞通知
     *
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable
     */
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        log.info("http://環(huán)繞通知 start");
        //執(zhí)行目標(biāo)方法
        Object result = proceedingJoinPoint.proceed();
        //判斷目標(biāo)方法的返回值類型
        if (result instanceof List) {
            for (Object tmp : ((List) result)) {
                //數(shù)據(jù)脫敏處理邏輯
                this.deepProcess(tmp);
            }
        } else {
            this.deepProcess(result);
        }
        log.info("http://環(huán)繞通知 end");
        return result;
    }


    public void deepProcess(Object obj) throws IllegalAccessException {
        if (obj != null) {
            //取出輸出對象的所有字段屬性,并遍歷
            Field[] declaredFields = obj.getClass().getDeclaredFields();
            for (Field declaredField : declaredFields) {
                //判斷字段屬性上是否標(biāo)記DecryptField注解
                if (declaredField.isAnnotationPresent(DecryptField.class)) {
                    //如果判斷結(jié)果為真,則取出字段屬性數(shù)據(jù)進(jìn)行解密處理
                    declaredField.setAccessible(true);
                    Object valObj = declaredField.get(obj);
                    if (valObj != null) {
                        String value = valObj.toString();
                        //加密數(shù)據(jù)的解密處理
                        value = this.decrypt(value);
                        DecryptField annotation = declaredField.getAnnotation(DecryptField.class);
                        boolean open = annotation.open();
                        //把解密后的數(shù)據(jù)重新賦值
                        declaredField.set(obj, value);
                    }
                }
            }
        }
    }


    private String decrypt(String value) {
        //這里特別注意一下,對稱加密是根據(jù)密鑰進(jìn)行加密和解密的,加密和解密的密鑰是相同的,一旦泄漏,就無秘密可言,
        //“fanfu-csdn”就是我自定義的密鑰,這里僅作演示使用,實際業(yè)務(wù)中,這個密鑰要以安全的方式存儲;
        byte[] key = SecureUtil.generateKey(SymmetricAlgorithm.DES.getValue(), "fanfu-csdn".getBytes()).getEncoded();
        SymmetricCrypto aes = new SymmetricCrypto(SymmetricAlgorithm.DES, key);
        String decryptStr = aes.decryptStr(value);
        return decryptStr;
    }
}

加密結(jié)果

保護(hù)敏感數(shù)據(jù):Spring Boot中敏感字段加密解密的高效解決方案圖片

解密結(jié)果

保護(hù)敏感數(shù)據(jù):Spring Boot中敏感字段加密解密的高效解決方案圖片

總結(jié)

這篇著重和大家分享的內(nèi)容如下:

1、敏感數(shù)據(jù)的一些基礎(chǔ)概念;

2、敏感數(shù)據(jù)處理的解決思路;

3、敏感數(shù)據(jù)處理的具體實現(xiàn)方式;

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 亚洲H成年动漫在线观看不卡 | 女教师巨大乳孔中文字幕免费 | 日本国产成人精品视频 | 双性太子| 九九九九视频 | 色婷婷综合久久久中文字幕 | 日本三级斤 | 欧美男人的天堂 | 四虎在线免费 | 久久国产热视频99rev6 | 91韩国女主播 | 亚洲午夜精品久久久久久人妖 | 啊啊啊好大在线观看 | 免费国产高清精品一区在线 | 国产自拍啪啪 | 先锋资源av| 特黄一级| 国语精彩对白2021 | 性趣味商品推荐 | 公交车强校花系列小说 | 国产3p绿奴在线视频 | 国产精品亚洲专区一区 | 亚洲国产精久久久久久久 | b站免费| 日本成人高清视频 | 初尝黑人巨大h文 | 国产成人综合网亚洲欧美在线 | 无人区乱码1区2区3区网站 | 久久人妻少妇嫩草AV无码 | 5151hh四虎国产精品 | 极品ts赵恩静和直男激战啪啪 | 国产第一页在线视频 | 91庥豆果冻天美精东蜜桃传媒 | 深夜免费在线观看 | 国产福利片在线 易阳 | 国产精品成人自拍 | 国产成人8x视频一区二区 | 色男人网 | 午夜香蕉成视频人网站高清版 | 日本免费三区 | 天天中文|