阿里聚安全的應用漏洞掃描器中有證書弱校驗、主機名弱校驗、webview未校驗證書的檢測項,這些檢測項是針對APP採用HTTPS通訊時容易出現風險的地方而設。接下來介紹一下安全使用HTTPS的相關內容。html
HTTP協議是沒有加密的明文傳輸協議,若是APP採用HTTP傳輸數據,則會泄露傳輸內容,可能被中間人劫持,修改傳輸的內容。以下圖所示就是典型的APP HTTP通訊被運營商劫持修改,插入廣告:java
上圖是在個人住處,用WiFi打開某APP,頁面底部出現了一個拆紅包的廣告,點開之後是一個安裝APP的頁面,若是我用聯通的4G網絡打開,就不會出現這種狀況,說明小區運營商劫持了HTTP通訊,往APP的通訊中加入了本身的推廣內容,還有一些低俗的推廣廣告,這很影響用戶體驗。一些別有用心的人經過搭建公共WiFi,進行流量劫持、嗅探,能夠得到經過HTTP傳輸的敏感信息。python
爲了保護用戶的信息安全、保護本身的商業利益,減小攻擊面,咱們須要保障通訊信道的安全,採用開發方便的HTTPS是比較好的方式,比用私有協議要好,省時省力。可是若是HTTPS使用不當,就很難起到應有的保護效果。烏雲上有不少Android HTTPS使用不當致使產生風險的例子,如 wooyun-2010-07935八、wooyun-2010-08196六、wooyun-2010-080117,有興趣的話能夠去找找看看。android
HTTPS是HTTP over SSL/TLS,HTTP是應用層協議,TCP是傳輸層協議,在應用層和傳輸層之間,增長了一個安全套接層SSL/TLS:git
SSL/TLS層負責客戶端和服務器之間的加解密算法協商、密鑰交換、通訊鏈接的創建,安全鏈接的創建過程以下所示:github
HPPTS握手協議有很豐富的內容,建議讀者使用wireshark抓包進行分析,因爲篇幅所限,這裏再也不進一步深刻。web
信息安全的基礎依賴密碼學,密碼學涉及算法和密鑰,算法通常是公開的,而密鑰須要獲得妥善的保護,密鑰如何產生、分配、使用和回收,這涉及公鑰基礎設施。算法
公鑰基礎設施(PKI)是一組由硬件、軟件、參與者、管理政策與流程組成的基礎架構,其目的在於創造、管理、分配、使用、存儲以及撤銷數字證書。公鑰存儲在數字證書中,標準的數字證書通常由可信數字證書認證機構(CA,根證書頒發機構)簽發,此證書將用戶的身份跟公鑰連接在一塊兒。CA必須保證其簽發的每一個證書的用戶身份是惟一的。瀏覽器
連接關係(證書鏈)經過註冊和發佈過程建立,取決於擔保級別,連接關係可能由CA的各類軟件或在人爲監督下完成。PKI的肯定連接關係的這一角色稱爲註冊管理中心(RA,也稱中級證書頒發機構或者中間機構)。RA確保公鑰和我的身份連接,能夠防抵賴。若是沒有RA,CA的Root 證書遭到破壞或者泄露,由此CA頒發的其餘證書就所有失去了安全性,因此如今主流的商業數字證書機構CA通常都是提供三級證書,Root 證書籤發中級RA證書,由RA證書籤發用戶使用的證書。安全
X509證書鏈,左邊的是CA根證書,中間的是RA中間機構,右邊的是用戶:
www.google.com.hk 網站的證書鏈以下,CA證書機構是 GeoTrust Global CA,RA機構是 Google Internet Authority G2,網站的證書爲 *.google.com.hk:
HTTPS通訊所用到的證書由CA提供,須要在服務器中進行相應的設置才能生效。另外在咱們的客戶端設備中,只要訪問的HTTPS的網站所用的證書是可信CA根證書籤發的,若是這些CA又在瀏覽器或者操做系統的根信任列表中,就能夠直接訪問,而如12306.cn網站,它的證書是非可信CA提供的,是本身簽發的,因此在用谷歌瀏覽器打開時,會提示「您的鏈接不是私密鏈接」,證書是非可信CA頒發的:
因此在12306.cn的網站首頁會提示爲了咱們的購票順利,請下載安裝它的根證書,操做系統安裝後,就不會再有上圖的提示了。
HTTPS網站所用的證書可向可信CA機構申請,不過這一類基本上都是商業機構,申請證書須要繳費,通常是按年繳費,費用由於CA機構的不一樣而不一樣。若是隻是APP與後臺服務器進行HTTPS通訊,可使用openssl工具生成自簽發的數字證書,能夠節約費用,不過得妥善保護好證書私鑰,不能泄露或者丟失。HTTPS通訊所用的數字證書格式爲X.509。
自簽發數字證書步驟以下:
Step1 生成本身的CA根證書
生成CA私鑰文件ca.key:
openssl genrsa -out ca.key 1024
生成X.509證書籤名請求文件ca.csr:
openssl req -new -key ca_private.key -out ca.csr
在生成ca.csr的過程當中,會讓輸入一些組織信息等。
生成X.509格式的CA根證書ca_public.crt(公鑰證書):
openssl x509 -req -in ca.csr -signkey ca_private.key -out ca_public.crt
Step2 生成服務端證書
先生成服務器私鑰文件server_private.key:
openssl genrsa -out server_private.key 1024
根據服務器私鑰生成服務器公鑰文件server_public.pem:
openssl rsa -in server_private.key -pubout -out server_public.pem
服務器端須要向CA機構申請簽名證書,在申請簽名證書以前依然是建立本身的證書籤名請求文件server.csr:
openssl req -new -key server_prviate.key -out server.csr
對於用於HTTPS的CSR,Common Name必須和網站域名一致,以便以後進行Host Name校驗。
服務器端用server.csr文件向CA申請證書,簽名過程須要CA的公鑰證書和私鑰參與,最終頒發一個帶有CA簽名的服務器端證書server.crt:
openssl x509 -req -CA ca_public.crt -CAkey ca_private.key -CAcreateserial -in server.csr -out server.crt
若是服務器端還想校驗客戶端的證書,能夠按生成服務器端證書的形式來生成客戶端證書。
使用openssl查看證書信息:
openssl x509 -in server.crt -text -noout
用web.py搭建一個簡單的服務器測試生成的server.crt,文件webpytest.py爲:
在本地運行web服務器程序:
python webpytest.py 1234
在safari瀏覽器中輸入 https://0.0.0.0:1234 ,提示此證書無效(主機名不相符),由於在生成服務器端證書籤名請求文件server.csr時,在Common Name中輸入的是localhost,與0.0.0.0不符:
在safari瀏覽器中輸入 https://localhost:1234 ,再也不提示主機名不相符了,而是提示此證書是由未知頒發機構簽名的,由於是私有CA簽發的證書,私有CA不在瀏覽器或者操做系統的的根信任列表中:
還可用如下命令查看網站證書信息:
openssl s_client -connect localhost:1234
服務器端搭建成功,接下來說Android客戶端怎麼和服務端進行HTTPS通訊。
Android官網給出了使用HttpsURLConnection API訪問HTTPS的網站示例:
此方法的特色:
由Android系統校驗服務端數字證書的合法性,用可信CA簽發的數字證書的網站才能夠正常訪問,私有CA簽發的數字證書的網站沒法訪問。
不能抵禦在用戶設備上安裝證書(將中間人服務器的證書放到設備的信任列表中)進行中間人攻擊,作此類攻擊的通常是爲了分析應用和服務器的交互協議,找應用和服務器的其餘漏洞。
若是網站沒有啓用SSL site wide(use HTTPS only)或HSTS(HTTP Strict Transport Security)則沒法抵禦SSL Strip(HTTPS降級爲HTTP)攻擊,局域網攻擊,如針對免費WiFi。
若是要使用私有CA簽發的證書,必須重寫校驗證書鏈TrustManager中的方法,不然的話會出現javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found。可是在重寫TrustManger中的checkServerTrusted()不少開發者什麼也沒有作,會致使證書弱校驗(沒有真正校驗證書)。
以下是錯誤的寫法:
正確的寫法是真正實現TrustManger的checkServerTrusted(),對服務器證書域名進行強校驗或者真正實現HostnameVerifier的verify()方法。
真正實現TrustManger的checkServerTrusted()代碼以下:
其中serverCert是APP中預埋的服務器端公鑰證書,若是是以文件形式,其獲取爲以下形式:
對服務器證書域名進行強校驗:
真正實現HostnameVerifier的verify()方法:
另一種寫法證書鎖定,直接用預埋的證書來生成TrustManger,過程以下:
參數certStream是證書文件的InputSteam流:
另外能夠用如下命令查看服務器證書的公鑰:
keytool -printcert -rfc -file uwca.crt
直接複製粘貼能夠將公鑰信息硬編碼在代碼中:
能夠用如下形式獲取此公鑰對應的X.509證書:
除了使用Android系統提供的HttpsURLconnection進行https通訊,還有其餘的第三方庫可使用,以OKhttp3.0爲例,先看未校驗服務器端證書鏈、未校驗服務端證書域名的錯誤寫法:
這些錯誤的發生其實和HttpsURLConnection的其實相同,都涉及SSLContext和HostnameVerifier,聚安全應用掃描器都能掃出來這些潛在風險點,解決辦法也和2.3 節相同使用HttpsURLConnection都是真正實現TrustManager和HostnameVerifier中的方法。
目前不少應用都用webview加載H5頁面,若是服務端採用的是可信CA頒發的證書,在 webView.setWebViewClient(webviewClient) 時重載 WebViewClient的onReceivedSslError() ,若是出現證書錯誤,直接調用handler.proceed()會忽略錯誤繼續加載證書有問題的頁面,若是調用handler.cancel()能夠終止加載證書有問題的頁面,證書出現問題了,能夠提示用戶風險,讓用戶選擇加載與否,若是是須要安全級別比較高,能夠直接終止頁面加載,提示用戶網絡環境有風險:
不建議直接用handler.proceed(),聚安全的應用安全掃描器會掃出來直接調用handler.proceed()的狀況。
若是webview加載https須要強校驗服務端證書,能夠在 onPageStarted() 中用 HttpsURLConnection 強校驗證書的方式來校驗服務端證書,若是校驗不經過中止加載網頁。固然這樣會拖慢網頁的加載速度,須要進一步優化,具體優化的辦法不在本次討論範圍,這裏也不詳細講解了。
阿里聚安全的漏洞掃描器發現,不少APP都存在HTTPS使用不當的風險。正確使用HTTPS能有效抵禦在用戶設備上安裝證書進行中間人攻擊和SSL Strip攻擊。
可是上述方法都須要在客戶端中預埋證書文件,或者將證書硬編碼寫在代碼中,若是服務器端證書到期或者由於泄露等其餘緣由須要更換證書,也就必須強制用戶進行客戶端升級,體驗效果很差。阿里聚安全推出了一個能完美解決這個問題的安全組件。APP開發者只須要將公鑰放在安全組件中,安全組件的動態密鑰功能能夠實現公鑰的動態升級。
另外正確使用HTTPS並不是徹底可以防住客戶端的Hook分析修改,要想保證通訊安全,也須要依靠其餘方法,好比重要信息在交給HTTPS傳輸以前進行加密,另外實現客戶端請求的簽名處理,保證客戶端與服務端通訊請求不被僞造。目前阿里聚安全的安全組件已經具有以上全部功能,此外還有安全存儲、模擬器檢測,人機識別等功能。安全組件還具備實時更新客戶端模塊的功能,保證攻防對抗強度。
[1] Survival guides - TLS/SSL and SSL (X.509) Certificates,http://www.zytrax.com/tech/su...
[2] Public key infrastructure,https://en.wikipedia.org/wiki...
[3] http://www.barretlee.com/blog...
[4] Security with HTTPS and SSL,https://developer.android.com...
[5] 竊聽風暴:Android平臺https嗅探劫持漏洞,http://www.freebuf.com/articl...
[6] Android HTTPS中間人劫持漏洞淺析,https://jaq.alibaba.com/blog....
[7] 淺析HTTPS中間人攻擊與證書校驗,http://www.evil0x.com/posts/2...
[8] https://github.com/menjoo/And...
[9] https://github.com/square/okh...
[10] https://github.com/square/okh...
目錄