Swift 網路安全原理及實踐

發表於2016-06-01

原理部分

對稱加密

存在一個對稱金鑰,資訊用對稱金鑰加密,也用對稱金鑰解密。

非對稱加密

存在一個公鑰和一個私鑰,可以公鑰加密私鑰解密,也可以私鑰加密公鑰解密。

雜湊演算法

客戶端將傳輸的內容雜湊,得到數字摘要,隨內容一起發給伺服器,伺服器將得到的內容雜湊,與收到的數字摘要比較,若相同,則內容完整無誤。

HTTPS原理

HTTPS = HTTP + SSL
SSL協議規定了客戶端與伺服器之間如何安全保密的傳輸資訊。

SSL協議中一般先用 非對稱加密方式 傳輸 對稱加密方式 的金鑰,再用 對稱加密方式 的金鑰傳輸通訊內容。
(因為 對稱加密方式 簡單,快)

第一步:客戶端申請建立SSL會話。
第二步:伺服器把自己的證書(假定這個證書靠譜)發給客戶端,裡面有伺服器的公鑰。
第三步:客戶端把 對稱加密方式 的金鑰(一般被叫做master_secret)用伺服器的公鑰加密,生成pre_master_secret,發回給伺服器。
第四步:伺服器用自己的私鑰解密pre_master_secret,得到master_secret。
第五步及之後:客戶端將通訊內容及其數字摘要用master_secret加密後發給伺服器,伺服器用master_secret解密,得到內容,順便驗證完整性。反之也成立。

Charles及Wireshark如何幹掉HTTPS

Charles

簡單的講,中間人攻擊。
在上面的第二步,客戶端收到的不是伺服器的證書,是Charles的,如果客戶端信任了這個證書,就會把master_secret用Charles的公鑰加密,所以Charles就知道了master_secret,自然能解密你們之後傳送的內容。GG
防止方法:在客戶端中存一份自己伺服器的證書,第二步收到證書時進行比較。

Wireshark和Ethereal

你先把伺服器的私鑰告訴Wireshark
在上面第四步,Wireshark用伺服器的私鑰解密pre_master_secret,得到master_secret,也就可以解密你們之後傳送的內容。GG
防止方法:保管好你伺服器的私鑰。

實踐部分

HTTP是明文傳輸的,如果你不用HTTPS,也不自己加密,直接用HTTP傳賬號密碼的話,那你就完蛋了。
iOS9預設禁止HTTP,如果你一定要用也可以,自行谷歌設定方法。
毫無疑問你應該用HTTPS,但上HTTPS了就絕對安全了麼,不是,HTTPS防不住中間人攻擊。
實踐部分我準備講一下Swift+Alamofire條件下怎麼通過驗證證書防止中間人攻擊。這部分對應的原理就是上面的這句話:

 

在客戶端中存一份自己伺服器的證書,第二步收到證書時進行比較。

Alamofire封裝的太好了,一般的請求只用這一句就好了:

如果你點request進去,就會發現,執行request的是Alamofire的sharedInstance。
不幸的是,修改這個sharedInstance的ServerTrustPolicy並不是一件容易的事,所以你得自己搞一個manager出來了。
希望你的架構裡有網路層這個東西,也就是一個類似NetworkingManager的類,如果沒有,希望你看一下我這篇文章,畢竟沒單獨的網路層不是件好事。
好,假設你有NetworkingManager這個類,這個類的結構就按我上面那篇文章來構造了(就是任性),這個類有一個單例,每個API對應一個例項方法。

在NetworkingManager類裡面定義這麼個變數,Manager是Alamofire的管理類。
並增加一個這樣的初始化方法,或者在初始化方法裡面新增這樣的內容:

這裡有個問題等下講,先說它的意思:ServerTrustPolicy 是Alamofire裡面負責管理伺服器驗證的一個類,提供了這麼幾種驗證方法:

  • PerformDefaultEvaluation
    即預設,沒試過所以不知道這個預設到底安不安全..
  • PinCertificates
    驗證證書,即我使用的方法
  • PinPublicKeys
    驗證公鑰
  • DisableEvaluation
    不驗證,心真大..
  • CustomEvaluation
    DIY驗證,如果你夠6可以選這個

certificatesInBundle即你放在Bundle裡的證書,Alamofire把這個證書和前面第二步伺服器傳過來證書進行比對,如果不對拒絕通訊,Charles之類的中間人攻擊也就沒可乘之機了。

如何把證書放進Bundle? 拖進去,注意選中copyIfNeeded 和 下面你的 Target。
如果想測試一下,哪裡找證書?比如 https://api.douban.com/v2/book/1220562 這樣的HTTPS網站,你用瀏覽器開啟,位址列左邊都有個小鎖,點進去,找找找,最後找到證書,拖到桌面上,字尾可能為.cer什麼的。

你得到了一個serverTrustPolicy,也就是一個驗證策略,在這裡是用證書驗證的策略。
Alamofire或者說iOS允許你對不同的host執行不同的驗證策略,這個對應關係放在[String : ServerTrustPolicy]這樣的一個字典裡,左邊是host(不是整個URL)右邊是policy,也就是上面的serverTrustPolicies,你拿這個去生成ServerTrustPolicyManager,再利用Manager的初始化方法,為manager賦值。

怎麼知道一個URL的host是哪一部分?有個好方法,開一個playground,用整個URL字串做一個NSURL,然後取這個NSURL例項host,看右側返回值。

然後你就有了一個配置好的安全的Manager例項。

為了測試,我在網路層管理類裡面寫了個test函式,裡面用這個安全的manager去request:

然後在主VC裡這麼呼叫:

你就會發現,只有當你證書配置正確了,你才能得到json,如果沒放證書,或者沒放對,就會輸出錯誤。如果你證書沒配對,也就是Alamofire覺得伺服器給它的證書不對,就拒絕了與伺服器的通訊。

上面提到有一個問題,就是為什麼一定要在NetworkingManager這個類裡面設一個manager變數,直接在testSSL裡面定義,定義完了用不行麼?答案是不行,你得一直持有它,一旦Alamofire去切執行緒去處理網路請求了,你定義的manager就會被釋放了,manager一被釋放,請求自然就被取消了,所以你也拿不到json。因為通常情況下用的是Alamofire.sharedInstance,它一直存在,所以一般感覺不到這個問題。

文章內容到此結束,再夾點私貨..
創業中,網際網路醫療,公司需要招安卓、iOS、Web、後臺.. 就是都需要,地點上海,已談定種子輪融資,薪水高於市價,有期權,但是每個崗位招的人不多,需要有出色的技術能力,以及願意和我們一起change the world。
微博:@我偏笑_NSNirvana 歡迎私信。

相關文章