對于數字證書相關概念、android 裡 https 通信代碼就不再複述了,直接講問題。缺少相應的安全校驗很容易導緻中間人攻擊,而漏洞的形式主要有以下3種:
自定義<code>x509trustmanager</code>。在使用<code>httpsurlconnection</code>發起 https 請求的時候,提供了一個自定義的<code>x509trustmanager</code>,未實作安全校驗邏輯,下面片段就是常見的容易犯錯的代碼片段。如果不提供自定義的<code>x509trustmanager</code>,代碼運作起來可能會報異常(原因下文解釋),初學者就很容易在不明真相的情況下提供了一個自定義的<code>x509trustmanager</code>,卻忘記正确地實作相應的方法。本文重點介紹這種場景的處理方式。
自定義了<code>hostnameverifier</code>。在握手期間,如果 url 的主機名和伺服器的辨別主機名不比對,則驗證機制可以回調此接口的實作程式來确定是否應該允許此連接配接。如果回調内實作不恰當,預設接受所有域名,則有安全風險。代碼示例。
信任所有主機名。
分而治之,針對不同的漏洞點分别描述,這裡就講的修複方案主要是針對非浏覽器app,非浏覽器 app 的服務端通信對象比較固定,一般都是自家伺服器,可以做很多特定場景的定制化校驗。如果是浏覽器 app,校驗政策就有更通用一些。
自定義<code>x509trustmanager</code>。前面說到,當發起 https 請求時,可能抛起一個異常,以下面這段代碼為例(來自官方文檔):
它會抛出一個<code>sslhandshakeexception</code>的異常。
android 手機有一套共享證書的機制,如果目标 url 伺服器下發的證書不在已信任的證書清單裡,或者該證書是自簽名的,不是由權威機構頒發,那麼會出異常。對于我們這種非浏覽器 app 來說,如果提示使用者去下載下傳安裝證書,可能會顯得比較詭異。幸好還可以通過自定義的驗證機制讓證書通過驗證。驗證的思路有兩種:
不論是權威機構頒發的證書還是自簽名的,打包一份到 app 内部,比如存放在 asset 裡。通過這份内置的證書初始化一個<code>keystore</code>,然後用這個<code>keystore</code>去引導生成的<code>trustmanager</code>來提供驗證,具體代碼如下:
這樣就可以得到正确的輸出内容:
如果你用上述同樣的代碼通路 https://www.taobao.com/ 或者 https://www.baidu.com/ ,則會抛出那個<code>sslhandshakeexception</code>異常,也就是說對于特定證書生成的<code>trustmanager</code>,隻能驗證與特定伺服器建立安全連結,這樣就提高了安全性。如之前提到的,對于非浏覽器 app 來說,這是可以接受的。
同方案1,打包一份到證書到 app 内部,但不通過<code>keystore</code>去引導生成的<code>trustmanager</code>,而是幹脆直接自定義一個<code>trustmanager</code>,自己實作校驗邏輯;校驗邏輯主要包括:
伺服器證書是否過期
證書簽名是否合法
同樣上述代碼隻能通路 certs.cac.washington.edu 相關域名位址,如果通路 https://www.taobao.com/ 或者 https://www.baidu.com/ ,則會在<code>cert.verify(((x509certificate) ca).getpublickey());</code>處抛異常,導緻連接配接失敗。
自定義<code>hostnameverifier</code>,簡單的話就是根據域名進行字元串比對校驗;業務複雜的話,還可以結合配置中心、白名單、黑名單、正則比對等多級别動态校驗;總體來說邏輯還是比較簡單的,反正隻要正确地實作那個方法。
主機名驗證政策改成嚴格模式
<a href="http://security.tencent.com/index.php/blog/msg/41">竊聽風暴: android平台https嗅探劫持漏洞</a>
<a href="http://drops.wooyun.org/tips/3296">android證書信任問題與大表哥</a>
<a href="http://jaq.alibaba.com/blog.htm?id=60">android https中間人劫持漏洞淺析</a>
<a href="http://drops.wooyun.org/tips/2775">數字證書及其在安全測試中的應用</a>
<a href="http://www.wooyun.org/bugs/wooyun-2014-080117">wooyun-2014-080117</a>
<a href="http://www.wooyun.org/bugs/wooyun-2014-079358">wooyun-2014-79358</a>
<a href="http://www.pianyissl.com/support/lists/1">ssl證書百科</a>
<a href="http://developer.android.com/intl/zh-cn/training/articles/security-ssl.html#commonhostnameprobs">security with https and ssl</a>
<a href="http://www.oschina.net/translate/android-security-implementation-of-self-signed-ssl">為你的安卓應用實作自簽名的 ssl 證書</a>
<a href="http://frank-zhu.github.io/android/2014/12/26/android-https-ssl/">android https ssl雙向驗證</a>
<a href="https://www.securecoding.cert.org/confluence/pages/viewpage.action?pageid=134807561">drd19. properly verify server certificate on ssl/tls</a>