引言
最近LZ在公司里接了一個活,要發布一些服務給公司的合作伙伴調用。這種工作LZ可謂是輕車熟路,之前已經做了無數服務端。不過與以往不同的是,這次的服務是要發布在互聯網上的,因此不能再像之前的套路一樣。之前的系統交互都是公司內網之間的,因此不存在數據安全問題。
這次不得不考慮數據的安全性,因此LZ最近就苦逼的開始研究各種加密算法。前后一共用了三天時間,LZ終於把加密層做好了,盡管LZ對各種加密算法的原理一概不知,但應該也算夠用了。畢竟LZ沒打算做一個絕對安全的系統(事實上這也是不可能的),只要能阻止90%的黑客即可。
方案制定
開始的時候,首先要制定方案,應用層的協議采用http,這點是確定的。對於加密,LZ想來想去,基本上有兩種選擇。
第一種是傳統的辦法,使用自簽名證書,借用jdk和web容器的ssl層實現,這種方法比較常用,也比較省事。
第二種是手動編程的方法,類似於自己寫了一層ssl的實現。原理也很簡單,對方把數據加密后傳給LZ的服務端,LZ這邊解密后該怎么處理就怎么處理,完事以后把響應的數據加密傳給客戶端,客戶端解密之后該怎么處理就怎么處理。
經過一番實驗和思考,LZ還是決定采用第二種方法。主要原因是,這種方式更加靈活,加密方案是LZ可以隨意更改的(比如把其中的某個算法用別的算法替換)。還有一點原因是,自己寫的東西更加容易掌控,如果加密層出現問題,LZ作為PM可以更快的定位問題。最后一點原因是,基於算法而不是基於Java類庫,更容易制作各種語言的客戶端。
代碼設計
方案基本確定,接下來就是代碼設計。代碼設計分為客戶端和服務端,作為客戶端,LZ可以提供公用的加密解密組件給合作伙伴調用(比如java客戶端,php客戶端,.NET客戶端等等)。作為服務端,LZ只需要過濾器和定制視圖就可以輕易完成加密和解密的工作。
最終寫出來的客戶端API如下:
HttpsHelper.sendJsonAndGetJson(JSONObject json);
HttpsHelper.sendJsonAndGetJson(JSONObject json,int timeout);
以上就是客戶端組件公布的兩個方法,方法的作用很好理解,LZ就不多說了。在方法的實現當中,LZ已經幫客戶端完成了加密和解密操作。當然,使用這個客戶端的前提是,得到LZ給予的授權碼。
服務端需要一個過濾器和一個定制的json視圖。
SecurityFilter
JsonView
由於LZ發布的是restful風格的服務,因此使用的mvc框架是spring mvc。這兩個類的具體代碼這里就不貼了,總之過濾器完成請求參數的解密,視圖完成響應結果的加密。
ssl層實現
以上基本上已經完成了整個加密解密功能的設計,接下來的工作就是將工作落實到實處,到底加密算法如何選擇?
之前LZ對加密解密算法可謂是大大的小白,就知道一個md5算法,一般是用於密碼加密的。這下可難倒LZ了,不過沒關系,有百度和google,還有什么不能在幾天之內學到的東西嗎。
經過一番百度和google,LZ發現算法主要分為以下三種:
1,不可逆加密算法,比如md5就是這樣一種,這種算法一般用於校驗,比如校驗用戶的密碼對不對。
2,對稱加密算法,這種算法是可逆的,兩邊擁有同一個密鑰,使用這個密鑰可以對數據加密和解密,一般用於數據加密傳輸。特點是速度快,但安全性相對於非對稱加密較低。
3,非對稱加密算法,這種算法依然是可逆的,兩邊擁有不同的密鑰,一個叫公鑰,一個叫私鑰,兩邊也都可以對數據加密和解密,一般用於數字簽名。特點是速度較慢,但安全性相對於對稱加密更高。
之前LZ聽說過ssl的實現是幾種算法混合使用的,這給了LZ很大的啟示。既然每種算法都有它的優勢,我們為何不混合使用呢。
於是,LZ想來想去(主要是在公車上以及廁所思考),決定使用md5(不可逆加密)+des(對稱加密)+rsa(非對稱加密)的加密方式,編碼格式可以使用Base64。來看看LZ的需求,主要有兩點。
1,客戶端需要LZ授權,也就是說LZ發布的服務不是誰想調就能調的。
2,數據在傳輸過程中是加密的,並且安全性要等同於非對稱加密算法的安全性,但性能要等同於對稱加密的速度。
我們來看看以上的算法實現能否滿足需要,過程是這樣的。
1,假設LZ給客戶端一個授權碼,比如123456。再假設客戶端現在需要傳的數據是{"name":"xiaolongzuo"}。(請求數據和響應數據都是json格式)
2,客戶端需要先對123456進行md5加密,然后放入到傳輸數據中。也就是傳輸的數據會變成{"name":"xiaolongzuo","verifyCode":"md5(123456)"}
3,客戶端生成des的隨機密鑰(注意,對稱密鑰每次都是隨機生成的),假設是abcdef,客戶端使用該密鑰對傳輸數據進行des加密,並且對隨機密鑰進行rsa加密,最終拼成一個json。也就是最終傳輸的數據會變成{"privateKey":"rsa(abcdef)","data":"des({"name":"xiaolongzuo","verifyCode":"md5(123456)"})"}
4,服務端使用相反的過程對數據進行解密即可,並驗證解密后的授權碼md5(123456)是否存在,如果不存在,則認為該客戶端未被授權。當服務端返回數據時,依舊使用abcdef對數據進行des加密即可。
安全性分析:假設以上的數據被黑客攔截,那么黑客最主要做的就是破解rsa算法的私鑰(私鑰只有LZ有,客戶端組件中會附帶公鑰),這個問題聽說是比較難的,具體為什么,這就不是LZ需要考慮的了,LZ還沒這個能力。基於這個前提,LZ可以認為傳輸的數據還是比較安全的。
性能分析:由於我們的rsa只對長度比較短的des私鑰進行加密,因此非對稱加密速度慢的特點並不會影響我們太多。幾乎上所有的傳輸數據,我們都是使用的des進行加密,因此在速度上,幾乎等同於對稱加密的速度。
小結
由於源代碼是公司所有,因此LZ這里不方便貼出來,但是整個思路這里已經闡述的非常清晰了。
通過這次的簡單學習,也不難發現,帶着目的的學習才是最高效率的學習。試想一下,如果LZ只是閑來無事,隨便看看加密算法,相信不會在這么短的時間內搞清楚,並且學會一些基礎的使用方法。所以事實證明,學習任何知識,最好的辦法就是利用這個知識做一個東西出來。