spring-boot-starter-encrypt
前言
前后端分離的開(kāi)發(fā)方式,我們以接口為標(biāo)準(zhǔn)來(lái)進(jìn)行推動(dòng),定義好接口,各自開(kāi)發(fā)自己的功能,最后進(jìn)行聯(lián)調(diào)整合。無(wú)論是開(kāi)發(fā)原生的APP還是webapp還是PC端的軟件,只要是前后端分離的模式,就避免不了調(diào)用后端提供的接口來(lái)進(jìn)行業(yè)務(wù)交互。
網(wǎng)頁(yè)或者app,只要抓下包就可以清楚的知道這個(gè)請(qǐng)求獲取到的數(shù)據(jù),這樣的接口對(duì)爬蟲(chóng)工程師來(lái)說(shuō)是一種福音,要抓你的數(shù)據(jù)簡(jiǎn)直輕而易舉。
數(shù)據(jù)的安全性非常重要,特別是用戶(hù)相關(guān)的信息,稍有不慎就會(huì)被不法分子盜用,所以我們對(duì)這塊要非常重視,容不得馬虎。
如何保證API調(diào)用時(shí)數(shù)據(jù)的安全性?
對(duì)所有請(qǐng)求和響應(yīng)都進(jìn)行加解密操作
方案有很多種,當(dāng)你做的越多,也就意味著安全性更高,今天我跟大家來(lái)介紹一下對(duì)所有請(qǐng)求和響應(yīng)都進(jìn)行加解密操作的方案,即使能抓包,即使能調(diào)用我的接口,但是我返回的數(shù)據(jù)是加密的,只要加密算法夠安全,你得到了我的加密內(nèi)容也對(duì)我沒(méi)什么影響。
像這種工作最好做成統(tǒng)一處理的,你不能讓每個(gè)開(kāi)發(fā)都去關(guān)注這件事情,如果讓每個(gè)開(kāi)發(fā)去關(guān)注這件事情就很麻煩了,返回?cái)?shù)據(jù)時(shí)還得手動(dòng)調(diào)用下加密的方法,接收數(shù)據(jù)后還得調(diào)用下解密的方法。
為此,我基于Spring Boot封裝了一個(gè)Starter, 內(nèi)置了AES加密算法。GitHub地址如下:
github.com/yinjihuan/s…
先來(lái)看看怎么使用,可以下載源碼,然后引入即可,然后在啟動(dòng)類(lèi)上增加@EnableEncrypt注解開(kāi)啟加解密操作:
@EnableEncrypt @SpringBootApplication public class App {public static void main(String[] args) {SpringApplication.run(App.class, args);} } 復(fù)制代碼增加加密的key配置:
spring.encrypt.key=abcdef0123456789 spring.encrypt.debug=false 復(fù)制代碼- spring.encrypt.key:加密key,必須是16位
- spring.encrypt.debug:是否開(kāi)啟調(diào)試模式,默認(rèn)為false,如果為true則不啟用加解密操作
為了考慮通用性,不會(huì)對(duì)所有請(qǐng)求都執(zhí)行加解密,基于注解來(lái)做控制
響應(yīng)數(shù)據(jù)需要加密的話(huà),就在Controller的方法上加@Encrypt注解即可。
@Encrypt @GetMapping("/list") public Response queryNews(String city) {return Response.ok(city); }復(fù)制代碼當(dāng)我們?cè)L問(wèn)/list接口時(shí),返回的數(shù)據(jù)就是加密之后base64編碼的格式。
還有一種操作就是前段提交的數(shù)據(jù),分為2種情況,一種是get請(qǐng)求,這種暫時(shí)沒(méi)處理,后面再考慮,目前只處理的post請(qǐng)求,基于json格式提交的方式,也就是說(shuō)后臺(tái)需要用@RequestBody接收數(shù)據(jù)才行, 需要解密的操作我們加上@Decrypt注解即可。
@Decrypt @PostMapping("/save") public Response savePageLog(@RequestBody PageLogParam logParam, HttpServletRequest request) {pageLogService.save(logParam);return Response.ok(); }復(fù)制代碼加了@Decrypt注解后,前端提交的數(shù)據(jù)需要按照AES加密算法,進(jìn)行加密,然后提交到后端,后端這邊會(huì)自動(dòng)解密,然后再映射到參數(shù)對(duì)象中。
上面講解的都是后端的代碼,前端使用的話(huà)我們以js來(lái)講解,當(dāng)然你也能用別的語(yǔ)言來(lái)做,如果是原生的安卓app也是用java代碼來(lái)處理。
前端需要做的就2件事情:
js加密文件請(qǐng)參考我GitHub中encrypt中的aes.js,crypto-js.js,pad-zeropadding.js
我們以axios來(lái)作為請(qǐng)求數(shù)據(jù)的框架,用axios的攔截器來(lái)統(tǒng)一處理加密解密操作
首先還是要封裝一個(gè)js加解密的類(lèi),需要注意的是加密的key需要和后臺(tái)的對(duì)上,不然無(wú)法相互解密,代碼如下:
var key = CryptoJS.enc.Latin1.parse('abcdef0123456789'); var iv = CryptoJS.enc.Latin1.parse('abcdef0123456789');// 加密 function EncryptData(data) {var srcs = CryptoJS.enc.Utf8.parse(data);var encrypted = CryptoJS.AES.encrypt(srcs, key, {mode : CryptoJS.mode.ECB,padding : CryptoJS.pad.Pkcs7});return encrypted.toString(); }// 解密 function DecryptData(data) {var stime = new Date().getTime();var decrypt = CryptoJS.AES.decrypt(data, key, {mode : CryptoJS.mode.ECB,padding : CryptoJS.pad.Pkcs7});var result = JSON.parse(CryptoJS.enc.Utf8.stringify(decrypt).toString());var etime = new Date().getTime();console.log("DecryptData Time:" + (etime - stime));return result; } 復(fù)制代碼axios攔截器中統(tǒng)一處理代碼:
// 添加請(qǐng)求攔截器 axios.interceptors.request.use(function (config) {// 對(duì)所有POST請(qǐng)加密,必須是json數(shù)據(jù)提交,不支持表單if (config.method == "post") {config.data = EncryptData(JSON.stringify(config.data));}return config;}, function (error) {return Promise.reject(error); });// 添加響應(yīng)攔截器 axios.interceptors.response.use(function (response) {// 后端返回字符串表示需要解密操作if(typeof(response.data) == "string"){response.data = DecryptData(response.data);}return response;}, function (error) {return Promise.reject(error); }); 復(fù)制代碼到此為止,我們就為整個(gè)前后端交互的通信做了一個(gè)加密的操作,只要加密的key不泄露,別人得到你的數(shù)據(jù)也沒(méi)用,問(wèn)題是如何保證key不泄露呢?
服務(wù)端的安全性較高,可以存儲(chǔ)在數(shù)據(jù)庫(kù)中或者配置文件中,畢竟在我們自己的服務(wù)器上,最危險(xiǎn)的其實(shí)就時(shí)前端了,app還好,可以打包,但是要防止反編譯等等問(wèn)題。
如果是webapp則可以依賴(lài)于js加密來(lái)實(shí)現(xiàn),下面我給大家介紹一種動(dòng)態(tài)獲取加密key的方式,只不過(guò)實(shí)現(xiàn)起來(lái)比較復(fù)雜,我們不上代碼,只講思路:
加密算法有對(duì)稱(chēng)加密和非對(duì)稱(chēng)加密,AES是對(duì)稱(chēng)加密,RSA是非對(duì)稱(chēng)加密。之所以用AES加密數(shù)據(jù)是因?yàn)樾矢?#xff0c;RSA運(yùn)行速度慢,可以用于簽名操作。
我們可以用這2種算法互補(bǔ),來(lái)保證安全性,用RSA來(lái)加密傳輸AES的秘鑰,用AES來(lái)加密數(shù)據(jù),兩者相互結(jié)合,優(yōu)勢(shì)互補(bǔ)。
其實(shí)大家理解了HTTPS的原理的話(huà)對(duì)于下面的內(nèi)容應(yīng)該是一看就懂的,HTTPS比HTTP慢的原因都是因?yàn)樾枰尶蛻?hù)端與服務(wù)器端安全地協(xié)商出一個(gè)對(duì)稱(chēng)加密算法。剩下的就是通信時(shí)雙方使用這個(gè)對(duì)稱(chēng)加密算法進(jìn)行加密解密。
spring-boot-starter-encrypt原理
最后我們來(lái)簡(jiǎn)單的介紹下spring-boot-starter-encrypt的原理吧,也讓大家能夠理解為什么Spring Boot這么方便,只需要簡(jiǎn)單的配置一下就可以實(shí)現(xiàn)很多功能。
啟動(dòng)類(lèi)上的@EnableEncrypt注解是用來(lái)開(kāi)啟功能的,通過(guò)@Import導(dǎo)入自動(dòng)配置類(lèi)
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import({EncryptAutoConfiguration.class}) public @interface EnableEncrypt {} 復(fù)制代碼EncryptAutoConfiguration中配置請(qǐng)求和響應(yīng)的處理類(lèi),用的是Spring中的RequestBodyAdvice和ResponseBodyAdvice,在Spring中對(duì)請(qǐng)求進(jìn)行統(tǒng)計(jì)處理比較方便。如果還要更底層去封裝那就要從servlet那塊去處理了。
@Configuration @Component @EnableAutoConfiguration @EnableConfigurationProperties(EncryptProperties.class) public class EncryptAutoConfiguration {/*** 配置請(qǐng)求解密* @return*/@Beanpublic EncryptResponseBodyAdvice encryptResponseBodyAdvice() {return new EncryptResponseBodyAdvice();}/*** 配置請(qǐng)求加密* @return*/@Beanpublic EncryptRequestBodyAdvice encryptRequestBodyAdvice() {return new EncryptRequestBodyAdvice();}} 復(fù)制代碼通過(guò)RequestBodyAdvice和ResponseBodyAdvice就可以對(duì)請(qǐng)求響應(yīng)做處理了,大概的原理就是這么多了。
總結(jié)
以上是生活随笔為你收集整理的spring-boot-starter-encrypt的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 推荐三个可以裁剪视频的软件给你
- 下一篇: php seek_cur,Golang中