即時通訊安全篇(一):正确地理解和使用Android端加密算法

1、前言

即時通訊是互聯網的重要應用形态之一,安全性一直是開發者需要優先考慮的基礎問題,并不是使用了加密就絕對安全了,如果加密函數使用不正确,加密數據很容易受到逆向破解攻擊。如何正确地理解和使用加密技術則顯的尤其重要。

本文主要讨論針對Android這樣的移動端應用開發時,如何正确的理解目前常用的加密算法,為諸如即時通訊應用的實戰開發,如何在合适的場景下選擇适合的算法,提供一些參考。

2、系列文章

本文是IM通訊安全知識系列文章中的第1篇,總目錄如下:

即時通訊安全篇(一):正确地理解和使用Android端加密算法》(* 本文)

即時通訊安全篇(二):探讨組合加密算法在IM中的應用

即時通訊安全篇(三):常用加解密算法與通訊安全講解

即時通訊安全篇(四):實例分析Android中密鑰硬編碼的風險

即時通訊安全篇(五):對稱加密技術在Android上的應用實踐

即時通訊安全篇(六):非對稱加密技術的原理與應用實踐

即時通訊安全篇(七):用JWT技術解決IM系統Socket長連接的身份認證痛點

即時通訊安全篇(八):如果這樣來理解HTTPS原理,一篇就夠了

即時通訊安全篇(九):你知道,HTTPS用的是對稱加密還是非對稱加密?

即時通訊安全篇(十):為什麼要用HTTPS?深入淺出,探密短連接的安全性

即時通訊安全篇(十一):IM聊天系統安全手段之通信連接層加密技術

即時通訊安全篇(十二):IM聊天系統安全手段之傳輸内容端到端加密技術

即時通訊安全篇(十三):信創必學,一文讀懂什麼是國密算法

即時通訊安全篇(十四):網絡端口的安全防護技術實踐

即時通訊安全篇(十五):詳解硬編碼密碼的洩漏風險及其掃描原理和工具

3、密碼學基本概念

密碼學的三大作用:加密( Encryption)、認證(Authentication),鑒定(Identification) 。

加密:防止壞人獲取你的數據。

認證:防止壞人修改了你的數據而你卻并沒有發現。

鑒權:防止壞人假冒你的身份。

明文、密文、密鑰、對稱加密算法、非對稱加密算法,這些基本概念和加密算法原理就不展開叙述了。

4、Android SDK提供的API

Android SDK使用的API和JAVA提供的基本相似,由以下部分組成:

Java Cryptography Architecture:JCA,java加密體系結構;

Java Cryptography Extension:JCE,Java加密擴展包);

Java Secure Sockets Extension:JSSE,Java安全套接字擴展包;

Java Authentication and Authentication Service:JAAS,Java 鑒别與安全服務。

JCA提供基本的加密框架,如證書、數字簽名、消息摘要和密鑰對産生器,對應的Android API中的以下幾個包:

...

JCE擴展了JCA,提供了各種加密算法、摘要算法、密鑰管理等功能,對應的Android API中的以下幾個包:

...

JSSE提供了SSL(基于安全套接層)的加密功能,使用HTTPS加密傳輸使用,對應的Android API主要是java.net.ssl包中。

JAAS 提供了在Java平台上進行用戶身份鑒别的功能。對應的Android API主要在以下幾個包:

...

它們其實隻是一組接口,實際的算法是可由不同的Provider提供,Android API默認的Provider主要是是Bouncy Castle和OpenSSL。 此外Android API還提供了android.security和android.security.keystore(API 23新增)來管理keychain和keystore。

5、常用算法之:Base64編碼

Base64編碼算法是一種用64個字符(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/)來表示任意二進制數據的方法。在計算機網絡發展的早期,由于“曆史原因”,電子郵件不支持非ASCII碼字符,如果要傳送的電子郵件帶有非ASCII碼字符(諸如中文)或者圖片,用戶收到的電子郵件将會是一堆亂碼,因此發明了Base64編碼算法。至于為何會亂碼?請大家自行Google。在加解密算法中,原始的數據和加密後的數據一般也是二進制數據,為了不傳輸出錯,方便保存或者調試代碼,一般需要對加密後的數據進行base64編碼。

Android提供了Base64編碼的工具類android.util.Base64,可以直接使用,不用自己去實現base64編碼的算法了。如:

...

【開發者建議】:

base64隻是一種編碼方式,并不是一種加密算法,不要使用base64來加密數據。

6、常用算法之:随機數生成器

在Android加密算法中需要随機數時要使用SecureRandom來獲取随機數。 如:

...

注意不要給SecureRandom設置種子。調用seeded constructor或者setSeed(byte[])是不安全的。SecureRandom()默認使用的是dev/urandom作為種子産生器,這個種子是不可預測的。

【開發者建議】:

不要使用Random類來獲取随機數。

在使用SecureRandom時候,不要設置種子。使用以下函數設置種子都是有風險的:

...

7、常用算法之:Hash算法

Hash算法是指任意長度的字符串輸入,此算法能給出固定n比特的字符串輸出,輸出的字符串一般稱為Hash值。

具有以下兩個特點:

抗碰撞性:尋找兩個不同輸入得到相同的輸出值在計算上是不可行的,需要大約  的時間去尋找到具有相同輸出的兩個輸入字符串。

不可逆:不可從結果推導出它的初始狀态。

抗碰撞性使Hash算法對原始輸入的任意一點更改,都會導緻産生不同的Hash值,因此Hash算法可以用來檢驗數據的完整性。我們經常見到在一些網站下載某個文件時,網站還提供了此文件的hash值,以供我們下載文件後檢驗文件是否被篡改。 不可逆的特性使Hash算法成為一種單向密碼體制,隻能加密不能解密,可以用來加密用戶的登錄密碼等憑證。

【開發者建議】:

1、建議使用SHA-256、SHA-3算法:

如使用SHA-256算法對message字符串做哈希:

...

2、不建議使用MD2、MD4、MD5、SHA-1、RIPEMD算法來加密用戶密碼等敏感信息:

這一類算法已經有很多破解辦法,例如md5算法,網上有很多查詢的字典庫,給出md5值,可以查到加密前的數據。

...

3、不要使用哈希函數做為對稱加密算法的簽名。

4、注意:當多個字符串串接後再做hash,要非常當心:

如:字符串S,字符串T,串接做hash,記為 H (S||T)。但是有可能發生以下情況。如“builtin||securely” 和 “built||insecurely”的hash值是完全一樣的。 如何修改從而避免上述問題産生? 改為H(length(S) || S || T)或者 H(H(S)||H(T))或者H(H(S)||T)。

實際開發過程中經常會對url的各個參數,做詞典排序,然後取參數名和值串接後加上某個SECRET字符串,計算出hash值,作為此URL的簽名, 如foo=1, bar=2, baz=3 排序後為bar=2, baz=3, foo=1,做hash的字符串為:SECRETbar2baz3foo1,在參數和值之間沒有分隔符,則”foo=bar”和”foob=ar”的hash值是一樣的,”foo=bar&fooble=baz”和”foo=barfooblebaz”一樣,這樣通過精心構造的惡意參數就有可能與正常參數的hash值一樣,從而騙過服務器的簽名校驗。

8、消息認證算法

要确保加密的消息不是别人僞造的,需要提供一個消息認證碼(MAC,Message authentication code)。 消息認證碼是帶密鑰的hash函數,基于密鑰和hash函數。密鑰雙方事先約定,不能讓第三方知道。

消息發送者使用MAC算法計算出消息的MAC值,追加到消息後面一起發送給接收者。接收者收到消息後,用相同的MAC算法計算接收到消息MAC值,并與接收到的MAC值對比是否一樣。

【開發者建議】:

建議使用HMAC-SHA256算法,避免使用CBC-MAC。 HMAC-SHA256例子如下:

...

9、對稱加密算法

在對稱加密算法中,數據發信方将明文(原始數據)和加密密鑰一起經過特殊加密算法處理後,使其變成複雜的加密密文發送出去。收信方收到密文後,若想解讀原文,則需要使用加密用過的密鑰及相同算法的逆算法對密文進行解密,才能使其恢複成可讀明文。在對稱加密算法中,使用的密鑰隻有一個,發收信雙方都使用這個密鑰對數據進行加密和解密,這就要求解密方事先必須知道加密密鑰。

該算法的缺點是,如果一旦密鑰洩漏,那麼加密的内容将都不可信了。

【開發者建議】:

1、建議使用AES算法。

2、DES默認的是56位的加密密鑰,已經不安全,不建議使用。

3、注意加密模式不要使用ECB模式。ECB模式不安全,說明問題的經典的三張圖片,如下:

明文是:

...

用ECB加密模式後:

...

用CBC加密模式後:

...

想更深入的了解關于對CBC加密模式的攻擊,可參看:《SSL/TLS協議安全系列:CBC 模式的弱安全性介紹(一)》。

4、Android 提供的AES加密算法API默認使用的是ECB模式,所以要顯式指定加密算法為:CBC或CFB模式,可帶上PKCS5Padding填充。AES密鑰長度最少是128位,推薦使用256位。

...

10、非對稱加密

非對稱加密算法需要兩個密鑰:公開密鑰(publickey)和私有密鑰(privatekey)。公開密鑰與私有密鑰是一對,如果用公開密鑰對數據進行加密,隻有用對應的私有密鑰才能解密;如果用私有密鑰對數據進行加密,那麼隻有用對應的公開密鑰才能解密(這個過程可以做數字簽名)。

非對稱加密主要使用的是RSA算法。

開發者建議:

1、注意密鑰長度不要低于512位,建議使用2048位的密鑰長度。 使用RSA進行數字簽名的算法,如:

...

2、使用RSA算法做加密,RSA加密算法應使用Cipher.getInstance(RSA/ECB/OAEPWithSHA256AndMGF1Padding),否則會存在重放攻擊的風險。 如:

...

11、加密算法PBE

PBE是一種基于口令的加密算法,其特點是使用口令代替了密鑰,而口令由用戶自己掌管,采用随機數雜湊多重加密等方法保證數據的安全性。

開發者建議:

使用基于口令的加密算法PBE時,生成密鑰時要加鹽,鹽的取值最好來自SecureRandom,并指定叠代次數。 如:

...

12、本文小結

幾條原則:

- 1、不要自己設計加密算法和協議,使用業界标準的算法。

- 2、對稱加密算法不要使用ECB模式,不建議使用DES算法。

- 3、要選擇合适長度的密鑰。

- 4、要确保随機數生成器的種子具有足夠的信息熵。

- 5、不要使用沒有消息認證的加密算法加密消息,無法防重放。

- 6、當多個字符串拼接後做hash,要非常當心。

- 7、當給算法加yan鹽取值時不要太短,不要重複。

- 8、使用初始化向量時IV時,IV為常量的CBC,CFB,GCM等和ECB一樣可以重放,即采用上一個消息的最後一塊密文作為下一個消息的IV,是不安全的。

- 9、密鑰應遵循的原則 :

(1)密鑰不能為常量,應随機,定期更換,如果加密數據時使用的密鑰為常量,則相同明文加密會得到相同的密文,很難防止字典攻擊。

(2)開發同學要防範密鑰硬編碼的毛病。

而在實際開發中,密鑰如何保存始終是繞不過的坎?如果硬編碼在代碼中容易被逆向,如果放在設備的某個文件,也會被有經驗的破解者逆向找到,在這裡推薦阿裡聚安全的安全組件服務,其中的安全加密功能提供了開發者密鑰的安全管理與加密算法實現,保證密鑰的安全性,實現安全的加解密操作。

更多IM安全和架構設計資料

[1] 傳輸層安全協議SSL/TLS的Java平台實現簡介和Demo演示

[2] 理論聯系實際:一套典型的IM通信協議設計詳解(含安全層設計)

[3] 微信新一代通信安全解決方案:基于TLS1.3的MMTLS詳解

[4] 來自阿裡OpenIM:打造安全可靠即時通訊服務的技術實踐分享

[5] 移動端安全通信的利器——端到端加密(E2EE)技術詳解

[6] 通俗易懂:一篇掌握即時通訊的消息傳輸安全原理

[7] 快速讀懂量子通信、量子加密技術

[8] 一分鐘理解 HTTPS 到底解決了什麼問題

[9] 基于Netty的IM聊天加密技術學習:一文理清常見的加密概念、術語等

[10] 手把手教你為基于Netty的IM生成自簽名SSL/TLS證書

[11] 微信技術分享:揭秘微信後台安全特征數據倉庫的架構設計

[12] 零基礎IM開發入門(二):什麼是IM系統的實時性?

[13] 零基礎IM開發入門(三):什麼是IM系統的可靠性?

[14] 零基礎IM開發入門(四):什麼是IM系統的消息時序一緻性?

[15] 新手入門一篇就夠:從零開發移動端IM

[16] 轉轉平台IM系統架構設計與實踐(一):整體架構設計

[17] 基于實踐:一套百萬消息量小規模IM系統技術要點總結

[18] 一套億級用戶的IM架構技術幹貨(上篇):整體架構、服務拆分等

[19] 一套億級用戶的IM架構技術幹貨(下篇):可靠性、有序性、弱網優化等

[20] 一套海量在線用戶的移動端IM架構設計實踐分享(含詳細圖文)

[21] 一套原創分布式即時通訊(IM)系統理論架構方案

(原文鍊接:http://jaq.alibaba.com/community/art/show?articleid=209

添加新評論

暱稱
郵箱
網站