歡迎來到山東省大學生網絡安全技能大賽!
首頁 > 學習園地

Android安全開發之安全使用HTTPS

發布人:admin 發布時間:2016-10-27 瀏覽數:1702

1、HTTPS簡介

  阿里聚安全的應用漏洞掃描器中有證書弱校驗、主機名弱校驗、webview未校驗證書的檢測項,這些檢測項是針對APP采用HTTPS通信時容易出現風險的地方而設。接下來介紹一下安全使用HTTPS的相關內容。

  1.1 為何需要HTTPS

  HTTP協議是沒有加密的明文傳輸協議,如果APP采用HTTP傳輸數據,則會泄露傳輸內容,可能被中間人劫持,修改傳輸的內容。如下圖所示就是典型的APP HTTP通信被運營商劫持修改,插入廣告:

\

  上圖是在我的住處,用WiFi打開某APP,頁面底部出現了一個拆紅包的廣告,點開以后是一個安裝APP的頁面,如果我用聯通4G網絡打開,就不會出現這種情況,說明小區運營商劫持了HTTP通信,往APP的通信中加入了自己的推廣內容,還有一些低俗的推廣廣告,這很影響用戶體驗。一些別有用心的人通過搭建公共WiFi,進行流量劫持、嗅探,可以獲得通過HTTP傳輸的敏感信息。

  為了保護用戶的信息安全、保護自己的商業利益,減少攻擊面,我們需要保障通信信道的安全,采用開發方便的HTTPS是比較好的方式,比用私有協議要好,省時省力。但是如果HTTPS使用不當,就很難起到應有的保護效果。烏云上有很多Android HTTPS使用不當導致產生風險的例子,如wooyun-2010-079358、wooyun-2010-081966、wooyun-2010-080117,有興趣的話可以去找找看看。

  1.2 HTTPS通信原理

  HTTPS是HTTP overSSL/TLS,HTTP是應用層協議,TCP是傳輸層協議,在應用層和傳輸層之間,增加了一個安全套接層SSL/TLS:

\

  SSL/TLS層負責客戶端和服務器之間的加解密算法協商、密鑰交換、通信連接的建立,安全連接的建立過程如下所示:

\

  HPPTS握手協議有很豐富的內容,建議讀者使用wireshark抓包進行分析,由于篇幅所限,這里不再進一步深入。

  2、如何使用HTTPS2.1 數字證書、CA與HTTPS

  信息安全的基礎依賴密碼學,密碼學涉及算法和密鑰,算法一般是公開的,而密鑰需要得到妥善的保護,密鑰如何產生、分配、使用和回收,這涉及公鑰基礎設施。

  公鑰基礎設施(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的網站首頁會提示為了我們的購票順利,請下載安裝它的根證書,操作系統安裝后,就不會再有上圖的提示了。

  2.2 自有數字證書的生成

  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通信。

  2.3 使用HttpsURLConnection進行HTTPS通信

  Android官網給出了使用HttpsURLConnection API訪問HTTPS的網站示例:

\

  此方法的特點:

  由Android系統校驗服務端數字證書的合法性,用可信CA簽發的數字證書的網站才可以正常訪問,私有CA簽發的數字證書的網站無法訪問。 不能抵御在用戶設備上安裝證書(將中間人服務器的證書放到設備的信任列表中)進行中間人攻擊,做此類攻擊的一般是為了分析應用和服務器的交互協議,找應用和服務器的其他漏洞。 如果網站沒有啟用SSLsite 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證書:

\

  2.4 使用OKHttp3.0進行HTTPS通信

  除了使用Android系統提供的HttpsURLconnection進行https通信,還有其他的第三方庫可以使用,以OKhttp3.0為例,先看未校驗服務器端證書鏈、未校驗服務端證書域名的錯誤寫法:

\

  這些錯誤的發生其實和HttpsURLConnection的其實相同,都涉及SSLContext和HostnameVerifier,聚安全應用掃描器都能掃出來這些潛在風險點,解決辦法也和2.3 節相同使用HttpsURLConnection都是真正實現TrustManager和HostnameVerifier中的方法。

  2.5 Webview的HTTPS安全

  目前很多應用都用webview加載H5頁面,如果服務端采用的是可信CA頒發的證書,在webView.setWebViewClient(webviewClient)時重載WebViewClient的onReceivedSslError(),如果出現證書錯誤,直接調用handler.proceed()會忽略錯誤繼續加載證書有問題的頁面,如果調用handler.cancel()可以終止加載證書有問題的頁面,證書出現問題了,可以提示用戶風險,讓用戶選擇加載與否,如果是需要安全級別比較高,可以直接終止頁面加載,提示用戶網絡環境有風險:

\

  不建議直接用handler.proceed(),聚安全的應用安全掃描器會掃出來直接調用handler.proceed()的情況。

  如果webview加載https需要強校驗服務端證書,可以在onPageStarted()中用HttpsURLConnection強校驗證書的方式來校驗服務端證書,如果校驗不通過停止加載網頁。當然這樣會拖慢網頁的加載速度,需要進一步優化,具體優化的辦法不在本次討論范圍,這里也不詳細講解了。

  3、阿里聚安全對開發者建議

  阿里聚安全的漏洞掃描器發現,很多APP都存在HTTPS使用不當的風險。正確使用HTTPS能有效抵御在用戶設備上安裝證書進行中間人攻擊和SSL Strip攻擊。

  但是上述方法都需要在客戶端中預埋證書文件,或者將證書硬編碼寫在代碼中,如果服務器端證書到期或者因為泄露等其他原因需要更換證書,也就必須強制用戶進行客戶端升級,體驗效果不好。阿里聚安全推出了一個能完美解決這個問題的安全組件。APP開發者只需要將公鑰放在安全組件中,安全組件的動態密鑰功能可以實現公鑰的動態升級。

  另外正確使用HTTPS并非完全能夠防住客戶端的Hook分析修改,要想保證通信安全,也需要依靠其他方法,比如重要信息在交給HTTPS傳輸之前進行加密,另外實現客戶端請求的簽名處理,保證客戶端與服務端通信請求不被偽造。目前阿里聚安全的安全組件已經具備以上所有功能,此外還有安全存儲、模擬器檢測,人機識別等功能。安全組件還具有實時更新客戶端模塊的功能,保證攻防對抗強度。