以前如果我們忘記了登入密碼,通常可以通過“找回密碼”這樣的方式拿回密碼,那說明你的隱私資料在他們的資料庫中是明文儲存的,現在請切記:如果哪個平臺還有這樣的方式請立刻馬上登出你的賬號,並避免在任何其他平臺使用這個平臺使用過的密碼。請堅信:在網路世界中,只要是明文存在或可逆的東西,都是不安全的。沒有哪家公司會告訴你他們的資料庫被拖庫過,你更無法想象現在的黑色產業早已讓你毫無隱私。
千萬別一個密碼走天下,一定要定期改密碼!
道高一尺魔高一丈,對使用者隱私及一些敏感資料的保護越來越重要,在iOS中,蘋果封裝了Security.framework、CommonCrypto.framework這兩個保護資訊保安的庫,為我們提供了安全相關的通用API:- RSA:公私鑰的生成、公鑰加密、私鑰解密、私鑰簽名、公鑰驗籤功能,證書資訊的讀取,以及金鑰在KeyChain中儲存,查詢,刪除等功能
- 雜湊:SHA1、SHA224、SHA256、SHA384、SHA512 MD2、MD4、MD5
- 對稱加密:DES、3DES、AES
這一篇文章,我們就以“使用者輸入密碼,登入,服務端驗證使用者資訊,使用者上傳隱私資料”這個常見場景為例,分享一些密碼學常識和加密時常用的防破解技巧,至於上述演算法相關API的使用,文末我會附上iOS中所有常用加密API使用的demo,這裡就不浪費篇幅貼程式碼了。先說兩個保護使用者隱私的原則:
- 網路上不允許明文傳遞使用者隱私資訊
- 本地不允許明文儲存使用者隱私資訊
再瞭解下幾種演算法的特點:
對稱加密
- 加密解密共用一個金鑰
- DES 資料加密標準,安全強度不夠已經很少用了
- 3DES 使用三個金鑰對相同的資料執行三次加密 強度略高,但金鑰的保護一直是個隱患所以也不常用
- AES 高階密碼標準 用得最多
- 兩種常用加密模式:
- ECB:
最基本的加密方式,無初始向量,相同的明文永遠生成不變的密文,容易受到密碼本重放攻擊,很少用 - CBC:
明文被加密前要與前面的密文進行異或運算後再加密,因此只要選擇不同的初始向量,相同的密文加密後會形成不同的密文,這是目前應用最廣泛的模式。CBC加密後的密文是上下文相關的,但明文的錯誤不會傳遞到後續分組,但如果一個分組丟失,後面的分組將全部作廢(同步錯誤)。
可以有效的保證密文的完整性,如果一個資料塊在傳遞是丟失或改變,後面的資料將無法正常解密。
- ECB:
RSA
關於RSA相關知識請參考:
非對稱加密--RSA原理淺析
RSA的主場-證書籤名之OpenSSL演示
這裡不再贅述。
雜湊演算法
也就是常說的雜湊函式,嚴格意義上它並不是一種加密演算法,但它常常與加密演算法一起出現,作為一種組合方式。雜湊具有以下特點:
- 演算法是公開的
- 對相同的資料運算,得到的結果是一樣的
- 同一演算法對不同的資料運算,得到的結果長度是固定的,如MD5的結果一定是128bit,32個字元(16進製表示),所以雜湊碰撞是必然的偶然
- 不可逆,但是可以通過彩虹表去反查詢
- 通常作為資訊“指紋”--資訊摘要,用來做資料識別(版權、搜尋引擎、數字簽名等)。
實際應用
知道了每種演算法的特點,回到應用場景:使用者輸完密碼點選登入時,我們如何保證使用者資訊是足夠安全的呢?
- 對稱加密:金鑰傳輸有隱患,且在客戶端加密前和服務端解密後會出現明文,不安全。
- RSA:安全性高,網路劫持很難破解,但是服務端拿到客戶端加密後的密文怎麼辦呢?用私鑰解密,解密之後拿到明文資訊?大忌,沒有哪個服務端是安全的,更沒法保證資料庫人員的個人洩露使用者資訊。不可取。
- 雜湊:
- 直接MD5?使用者輸入常規組合概率很大,暴力破解風險很高,不可取。本地加鹽,很變態的鹽?安全性有一定保障,缺點是鹽寫死在程式裡了,寫程式碼的人也有洩露的可能性,一旦洩漏結果是毀滅性的,不可取。
- HMAC:Keyed-Hashing for Message Authentication,這是一種使用單向雜湊函式來構造訊息認證碼的方案,而不是演算法。
在第一次註冊時,服務端下發一個隨機金鑰 n,這個金鑰會在客戶端和服務端都儲存一份(支援服務端更新),客戶端的 n 用作以後每次登入時的“鹽”參與第一次雜湊運算,並將第一次雜湊運算的結果 s 發給服務端作為使用者密碼資訊儲存到資料庫中,這樣使用者的真實密碼無論是客戶端還是服務端都不知道,也不存在資料庫被拖庫洩露的問題。服務端儲存的 n 用於當使用者換裝置登入或解除安裝重新裝時驗證通過後再次將 n 下發給客戶端儲存。
使用者每次登入時,伺服器會再動態下發一個隨機值作為金鑰,並在會話中記下這個隨機值 r,客戶端先用本地儲存的 n 對使用者密碼做雜湊運算得到 s ,再用 r 對 s 做一次MAC(Message Authentication Codes)運算並將運算結果傳送給服務端,服務端也從資料庫中取出使用者的密碼雜湊值做同樣的運算,並將結果與客戶端進行對比。為了防止網路中間人攻擊,還需將時間戳(伺服器時間,一般精確到分鐘)參與校驗,黑客就很難破解了。這是目前最主流的安全方案。
現在使用者登入成功,現在要上傳一份敏感資料,我們如何保證資料的完整性呢?結合上面的分析,推薦AES的CBC加密方式,安全性高,還能保證完整性,數字簽名同樣也可以驗證資料完整性,用RSA對資料的hash值進行加密,服務端接收完資料後,用私鑰解密得到hash值,與接收資料的hash值作比對。
補充:
iOS中常見加密演算法的使用:EncryptDemo
在Demo中,對稱加密AES的加密解密函式:
CCCryptorStatus CCCrypt(
CCOperation op, /* kCCEncrypt, etc. */
CCAlgorithm alg, /* kCCAlgorithmAES128, etc. */
CCOptions options, /* kCCOptionPKCS7Padding, etc. */
const void *key,
size_t keyLength,
const void *iv, /* optional initialization vector */
const void *dataIn, /* optional per op and alg */
size_t dataInLength,
void *dataOut, /* data RETURNED here */
size_t dataOutAvailable,
size_t *dataOutMoved)
API_AVAILABLE(macos(10.4), ios(2.0));
複製程式碼
呼叫CCCrypt時,使用者敏感資料不要直接作為引數傳遞,否則逆向很容易hook到,通常的做法是對敏感資料做異或、加鹽等處理,具體根據需要自己設計。
iOS app簽名機制詳解 推薦閱讀:
iOS應用簽名(上)
iOS應用簽名(下)
iOS中對鑰匙串的操作推薦:SSKeyChain
實踐出真知,我們下篇再會~
老規矩,有錯誤請積極指正,有問題請踴躍留言。
更多一手好文更新,請關注我的個人微信公眾號:面向未來程式設計
撒花✧(≖ ◡ ≖✿)