Android OKHttp源碼解析Https安全處理
Https
Https是Http協(xié)議加上下一層的SSL/TSL協(xié)議組成的,TSL是SSL的后繼版本,差別很小,可以理解為一個東西。進行Https連接時,會先進行TSL的握手,完成證書認證操作,產(chǎn)生對稱加密的公鑰、加密套件等參數(shù)。之后就可以使用這個公鑰進行對稱加密了。
Https的加密方式同時使用了非對稱加密和對稱加密:
- 使用反向的非對稱加密對證書進行簽名
- 在檢查通過的證書公鑰基礎(chǔ)上,利用非對稱加密產(chǎn)生對稱加密的公鑰
- 使用產(chǎn)生的公鑰,利用對稱加密交互傳輸?shù)臄?shù)據(jù)。
上面就是Https工作的大致流程,下面詳細介紹下加密的知識和握手。
加密知識
對于加密這種技術(shù),很早很早之前就有了。沒有加密的數(shù)據(jù),稱為明文,經(jīng)過加密的叫做密文。Http默認都是明文傳輸,這種方式很容易被監(jiān)聽或者修改。加密的最終目的,是保證機密性、完整性、可用性。
密碼是一套加密算法,使用計算機之前都是使用機械式后者密碼本進行操作。在使用計算機之后,加密的安全程度愈來越高,但是被解密也愈來愈容易。
秘鑰
如果光有密碼和原始數(shù)據(jù),那么破解會簡單很多,因為只要知道了密碼的加密方式,反向操作即可拿到明文數(shù)據(jù)。所以為了增加難度,增加了秘鑰。
現(xiàn)在密碼就需要兩個參數(shù)進行計算了,秘鑰+明文+密碼==密文。只拿到密碼和密文,是不能獲取原始明文,還需要秘鑰。破解的難度就更大了。
用秘鑰加密的技術(shù),又因為加密和解密秘鑰的情況分兩種。
對稱加密
加密和解密的秘鑰是相同的,這種加密方式被稱為對稱加密,使用的秘鑰被稱為公鑰。
對稱加密的速度很快,但是服務(wù)器需要把自己的公鑰傳到客戶端,客戶端使用這個公鑰對數(shù)據(jù)進行加密,服務(wù)器使用同樣的公鑰進行解密。
但是這種方式?jīng)]有辦法防止中間人攻擊,如果中間人篡改了傳輸?shù)墓€,使用自己的公鑰代替他,那么接可以截取發(fā)送方的數(shù)據(jù),使用自己的公鑰進行解密。
非對稱加密
加密和解密的秘鑰是不同的,這種加密方式被稱為非對稱加密,進行加密的是公共的公鑰,而進行解密的叫做私鑰。這樣只有私鑰的擁有者才可以解密數(shù)據(jù)。
反向的非對稱加密是數(shù)字簽名,也就是使用私鑰進行加密,使用公共的公鑰的進行解密,這樣就可以鑒定發(fā)送者的身份。也就是只有發(fā)送者才有私鑰。
非對稱加密的缺點是速度很慢,同樣也沒有辦法防止中間人攻擊,中間人截獲了服務(wù)器的公鑰。并用自己的公鑰代替,這樣也可以獲取發(fā)送者的數(shù)據(jù)。
Https的方案
因為對稱和非對稱加密都有自己的問題,都是因為公鑰的傳遞沒法保證安全性,中間人可以通過替換成自己的公鑰,完成截取的工作。
Https使用了混合的方式,同時使用了兩種方式,使用非對稱加密產(chǎn)生對稱加密的公鑰,再通過對稱加密進行處理。首先對稱加密比較快速相對于非對稱加密。所以還是使用對稱加密比較好,那么對稱加密的缺點時怎么保證公鑰能夠安全的交換呢。
這里可以使用非對稱加密傳輸這段公鑰。這樣這段公鑰就可以被安全的傳輸。因為只有服務(wù)器的私鑰才可以進行解密。非對稱加密有什么問題呢,就是不能判斷收到的公鑰是否就是真正的公鑰,是不是被篡改或者替換。怎么保證受到的公鑰就是合法的公鑰呢?
那就需要一個機構(gòu)來給這個公鑰背書,可以通過它保證這個公鑰是合法的,而承載公鑰的載體就是證書??蛻舳送ㄟ^證書進行驗證,完成公鑰的獲取。之后就可以通過這個公鑰完成非對稱加密傳輸。協(xié)商對稱加密所用的公鑰。
Https的方案大體就是這樣。 以上就是Https的基礎(chǔ)知識。下面分析下TSL的握手細節(jié)。
TSL握手
TSL的握手主要的目的要協(xié)商加密的算法、對稱加密的公鑰、TSL/SSL版本。
首先通過連接到服務(wù)器的443端口,通過TCP連接,這段是明文傳輸,用于溝通上面所說的參數(shù)。建立完成連接后就可以開始進行握手操作了。
握手如上圖所示,逐條分析下
- 客戶端發(fā)送 client hello的報文,發(fā)送了客戶端支持的協(xié)議版本、密碼套件、隨機數(shù)、壓縮算法等,服務(wù)器要在這之中選中一個自己支持的,如果自己都不支持,那么就會斷開連接。
- 服務(wù)器返回 server hello報文,內(nèi)含選中的版本、密碼套件、隨機數(shù)、壓縮算法等。并會返回自己的證書。
- 客戶端收到證書后,檢驗這個證書,檢驗分四步:時間有效性檢查、簽發(fā)的頒發(fā)者可信度檢測、簽名檢測、站點名稱檢測。如果四項檢測都通過了,那么就會取出證書中的公鑰。
- 通過上面產(chǎn)生的隨機數(shù),產(chǎn)生了Pre-master secret,該報文使用從證書中解密獲得的公鑰進行加密(其實就是服務(wù)器的公鑰),并通過公鑰加密傳輸?shù)椒?wù)端。通過這個數(shù)通過DH算法計算出MAC報文摘要和對稱加密的公鑰。 上面的方式就產(chǎn)生了可以進行對稱加密的公鑰。下面發(fā)送的數(shù)據(jù)就可以通過這個公鑰開始對稱加密了。
沒有用到數(shù)字證書? 傳輸?shù)淖C書使用了數(shù)字證書也就是反向的對稱加密,當收到證書,檢驗通過后,會使用CA的公鑰進行檢測,也就是CA使用了自己的私鑰進行了加密,只有CA知道私鑰。
隨機數(shù)怎么計算的?可以參考這里
隨機數(shù)計算
傳輸過程中,會涉及3個隨機數(shù),客戶端產(chǎn)生的/服務(wù)端產(chǎn)生的/Pre-master secret。 在傳輸Pre-master secret時,會使用從證書獲取的公開秘鑰,只有服務(wù)器才可以解密,對于客戶端:
當其生成了Pre-master secret之后,會結(jié)合原來的A、B隨機數(shù),用DH算法計算出一個master secret,緊接著根據(jù)這個master secret推導出hash secret和session secret。
對于服務(wù)端:
當其解密獲得了Pre-master secret之后,會結(jié)合原來的A、B隨機數(shù),用DH算法計算出一個master secret,緊接著根據(jù)這個master secret推導出hash secret和session secret。
在客戶端和服務(wù)端的master secret是依據(jù)三個隨機數(shù)推導出來的,它是不會在網(wǎng)絡(luò)上傳輸?shù)模挥须p方知道,不會有第三者知道。同時,客戶端推導出來的session secret和hash secret與服務(wù)端也是完全一樣的。
那么現(xiàn)在雙方如果開始使用對稱算法加密來進行通訊,使用哪個作為共享的密鑰呢?過程是這樣子的:
雙方使用對稱加密算法進行加密,用hash secret對HTTP報文 做一次運算生成一個MAC,附在HTTP報文的后面,然后用session-secret加密所有數(shù)據(jù)(HTTP+MAC),然后發(fā)送。
接收方則先用session-secret解密數(shù)據(jù),然后得到HTTP+MAC,再用相同的算法計算出自己的MAC,如果兩個MAC相等,證明數(shù)據(jù)沒有被篡改。
OkHttp的設(shè)計
OkHttp是支持自動的Https連接的,也就是我們默認訪問一個Https的網(wǎng)站,會自動的完成TSL的握手和加密。但是對于自簽名的證書還是需要我們進行配置的。
涉及的類
ConnectionSpec
:連接的參數(shù)配置,包括SSL/TLS的版本、密碼套件等,這個在OkHttpClient#connectionSpecs
進行配置,默認是具有SNI和ALPN等擴展功能的現(xiàn)代TLS和clear text即明文傳輸。SSL握手的前兩部就是溝通這部分參數(shù)的。CertificateChainCleaner
:證書鏈清理工具,用于省略無用的證書,過濾出一個列表,最后一個鏈結(jié)是受信任的證書。X509TrustManager
:此接口的實例管理哪些 X509 證書可用于驗證安全套接字的遠程端。 決策可能基于受信任的證書頒發(fā)機構(gòu)、證書撤銷列表、在線狀態(tài)檢查或其他方式。這個類對應上面證書檢測的簽發(fā)的頒發(fā)者可信度檢測、簽名檢測、時間有效性檢查。HostnameVerifier
:驗證主機名是否與服務(wù)器的身份驗證方案匹配??梢曰谧C書,也可以基于其他方式。這個用于上面說的驗證證書的站點名稱檢測。X509Certificate
:X.509 證書的抽象類。 這提供了一種訪問 X.509 證書所有屬性的標準方法。現(xiàn)有的證書都是X509類型的,這時一個標準。SSLSocketFactory
:這個是jdk提供的工具,負責SSLSocket
,SSLSocket
可以調(diào)用handShake進行ssl的握手。CertificatePinner
:固定證書配置,用于對握手通過的證書做固定驗證,也就是證書必須滿足固定證書的配置。 上面的類不但有jdk還有OkHttp的工具,共同完成了Https的工作。OkHttp大部分利用了jdk關(guān)注Https的支持。
OkHttpClient配置階段
OkHttpClient作為OkHttp的入口,可以對上面的類進行配置??聪略赽uidler里是怎么進行配置的。
單獨配置SSLSocketFactory
設(shè)置用于保護 HTTPS 連接的套接字工廠。如果未設(shè)置,將使用系統(tǒng)默認值。
public Builder sslSocketFactory(SSLSocketFactory sslSocketFactory) { if (sslSocketFactory == null) throw new NullPointerException("sslSocketFactory == null"); this.sslSocketFactory = sslSocketFactory; this.certificateChainCleaner = Platform.get().buildCertificateChainCleaner(sslSocketFactory); return this; }
同時配置SSLSocketFactory和X509TrustManager
可以通過sslSocketFactory方法,配置上面的兩個參數(shù),正常情況下,我們不需要配置,只需要采用系統(tǒng)默認的配置即可。
public Builder sslSocketFactory( SSLSocketFactory sslSocketFactory, X509TrustManager trustManager) { if (sslSocketFactory == null) throw new NullPointerException("sslSocketFactory == null"); if (trustManager == null) throw new NullPointerException("trustManager == null"); this.sslSocketFactory = sslSocketFactory; this.certificateChainCleaner = CertificateChainCleaner.get(trustManager); return this; }
配置HostnameVerifier
可以通過hostnameVerifier()配置hostnameVerifier,以達到我們檢測證書的站點名稱。
public Builder hostnameVerifier(HostnameVerifier hostnameVerifier) { if (hostnameVerifier == null) throw new NullPointerException("hostnameVerifier == null"); this.hostnameVerifier = hostnameVerifier; return this; }
HostnameVerifier
是一個接口,我們只要調(diào)用它的verify
方法就可以完成校驗,這個操作發(fā)生在Https握手完成后,系統(tǒng)提供了AbstractVerifier
骨架類進行配置。默認是OkHostnameVerifier
。
配置CertificatePinner
設(shè)置固定證書,我們可以創(chuàng)建一個CertificatePinner,CertificatePinner是一個實現(xiàn)好的類,我們只要傳入主機名稱和證書的SHA-256或者SHA-1 hashes即可。握手守信的證書必須通過配置的固定證書。如果不滿足,就會拋出異常,停止鏈接。
public Builder certificatePinner(CertificatePinner certificatePinner) { if (certificatePinner == null) throw new NullPointerException("certificatePinner == null"); this.certificatePinner = certificatePinner; return this; }
OkHttpClient參數(shù)處理階段
上面我們可以通過builder配置參數(shù),那么參數(shù)是如何進行處理的呢。我們配置不配置一個參數(shù)又有什么不同呢?
boolean isTLS = false; for (ConnectionSpec spec : connectionSpecs) { isTLS = isTLS || spec.isTls(); } if (builder.sslSocketFactory != null || !isTLS) { // 自定義或不使用Https this.sslSocketFactory = builder.sslSocketFactory; this.certificateChainCleaner = builder.certificateChainCleaner; } else { // 默認配置 X509TrustManager trustManager = Util.platformTrustManager(); this.sslSocketFactory = newSslSocketFactory(trustManager); this.certificateChainCleaner = CertificateChainCleaner.get(trustManager); } if (sslSocketFactory != null) { Platform.get().configureSslSocketFactory(sslSocketFactory); }
參數(shù)的處理代碼如上所示,先獲取鏈接的配置是否是TSL,除了明文連接外,都是使用TSL的。如果我們配置了自己的sslSocketFactory或者不是TSL連接(沒有配置sslSocketFactory),那么都會使用builde人內(nèi)部的sslSocketFactory。也就是說配置了,就使用配置的,沒有配置,如果當前不支持TSL,那么sslSocketFactory就為空。
如果沒有配置并且是TSL連接的話,這里就會使用默認的配置。這里的邏輯是先獲取X509TrustManager,再通過X509TrustManager獲取SslSocketFactory,通過SslSocketFactory再獲取CertificateChainCleaner。整體的依賴關(guān)系就是這樣。后面配置自定義證書時,也會使用這個依賴鏈。 依次看下每個過程:
X509TrustManager trustManager = Util.platformTrustManager();
public static X509TrustManager platformTrustManager() { try { TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init((KeyStore) null); TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) { throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers)); } return (X509TrustManager) trustManagers[0]; } catch (GeneralSecurityException e) { throw assertionError("No System TLS", e); // The system has no TLS. Just give up. } }
通過TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm());獲取默認的TrustManager工廠,調(diào)用init方法,這個方法傳入秘鑰庫,并使用證書頒發(fā)機構(gòu)和相關(guān)信任材料的來源初始化此工廠。通常使用傳入的KeyStore作為做出信任決策的基礎(chǔ)。我們自簽名的證書也會通過這個方法進行配置。
后面只餓極取出trustManagerFactory.getTrustManagers(),拿數(shù)組第一個作為最終的X509TrustManager。
this.sslSocketFactory = newSslSocketFactory(trustManager);
private static SSLSocketFactory newSslSocketFactory(X509TrustManager trustManager) { try { SSLContext sslContext = Platform.get().getSSLContext(); sslContext.init(null, new TrustManager[] { trustManager }, null); return sslContext.getSocketFactory(); } catch (GeneralSecurityException e) { throw assertionError("No System TLS", e); // The system has no TLS. Just give up. } }
獲取X509TrustManager后,這里通過Platform.get().getSSLContext()獲取SSLContext。
Platform.get()通過反射獲取了不同平臺的配置工具,這樣OKHttp就可以運行在不同的平臺上。獲取SSLContext后,就可以init方法,對SSLContext進行配置,調(diào)用getSocketFactory獲取最終的SSLSocketFactory。
this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
這里配置了CertificateChainCleaner,獲取trustManager中的可以用于驗證對等方的證書,之后創(chuàng)建一個BasicCertificateChainCleaner
。
通過上面的兩個配置的步驟,就完成了配置階段,看看在連接時是怎么使用Https的。
OkHttp連接Https階段
Https的握手發(fā)生在Http連接之后,在ConnectInterceptor
這個連接攔截器中。在調(diào)用完connectSocket后,就開始進行SSL的握手。因為Https需要默認連接443 端口,但是Http會連接80端口,這個邏輯是在哪兒配置的呢。在我們構(gòu)建請求的Request傳入的HttpUrl中,有一個port字段就是用于確定端口的。在獲取端口時,如果沒有進行顯式的配置。就會根據(jù)defaultPort()
進行配置。邏輯也比較簡單。所以connectSocket會直接連接443端口,為下面的SSL握手做了準備。
public static int defaultPort(String scheme) { if (scheme.equals("http")) { return 80; } else if (scheme.equals("https")) { return 443; } else { return -1; } }
進行SSL連接主要通過connectTls
進行。 通過下面的方法進行判斷。如果sslSocketFactory不為null,那么就會使用Https進行連接。
if (route.address().sslSocketFactory() == null)
private void connectTls(ConnectionSpecSelector connectionSpecSelector) throws IOException { Address address = route.address(); SSLSocketFactory sslSocketFactory = address.sslSocketFactory(); boolean success = false; SSLSocket sslSocket = null; try { // 創(chuàng)建SSLSocket,是對原始Socke的包裝 sslSocket = (SSLSocket) sslSocketFactory.createSocket( rawSocket, address.url().host(), address.url().port(), true /* autoClose */); // 配置SSL版本和密碼套件 ConnectionSpec connectionSpec = connectionSpecSelector.configureSecureSocket(sslSocket); if (connectionSpec.supportsTlsExtensions()) { // 配置SSL擴展 Platform.get().configureTlsExtensions( sslSocket, address.url().host(), address.protocols()); } // 進行握手 sslSocket.startHandshake(); // 等待握手完成 SSLSession sslSocketSession = sslSocket.getSession(); Handshake unverifiedHandshake = Handshake.get(sslSocketSession); // 進行證書域名確定 if (!address.hostnameVerifier().verify(address.url().host(), sslSocketSession)) { List<Certificate> peerCertificates = unverifiedHandshake.peerCertificates(); if (!peerCertificates.isEmpty()) { X509Certificate cert = (X509Certificate) peerCertificates.get(0); throw new SSLPeerUnverifiedException( "Hostname " + address.url().host() + " not verified:" + "\n certificate: " + CertificatePinner.pin(cert) + "\n DN: " + cert.getSubjectDN().getName() + "\n subjectAltNames: " + OkHostnameVerifier.allSubjectAltNames(cert)); } else { throw new SSLPeerUnverifiedException( "Hostname " + address.url().host() + " not verified (no certificates)"); } } // 檢測固定證書 address.certificatePinner().check(address.url().host(), unverifiedHandshake.peerCertificates()); // 握手成功,獲取Http協(xié)議 String maybeProtocol = connectionSpec.supportsTlsExtensions() ? Platform.get().getSelectedProtocol(sslSocket) : null; socket = sslSocket; source = Okio.buffer(Okio.source(socket)); sink = Okio.buffer(Okio.sink(socket)); handshake = unverifiedHandshake; protocol = maybeProtocol != null ? Protocol.get(maybeProtocol) : Protocol.HTTP_1_1; success = true; } catch (AssertionError e) { if (Util.isAndroidGetsocknameError(e)) throw new IOException(e); throw e; } finally { if (sslSocket != null) { Platform.get().afterHandshake(sslSocket); } if (!success) { closeQuietly(sslSocket); } } }
邏輯比較清晰,逐條分析下
- 通過
sslSocketFactory
創(chuàng)建SSLSocket
。通過SSLSocket
可以直接進行執(zhí)行SSL的握手。 - 傳入上面講到的TSL版本和密碼套件
- 配置SSL的擴展,這里如果
ALPN
的擴展,會寫上使用的Http版本,握完手后會取這個配置,并判斷是否使用Http2.0版本。 - 調(diào)用sslSocket.startHandshake(),進行握手。這時一個同步的操作,會阻塞當前線程,直到握手成功,如果中間出了什么問題,那么會直接拋出異常。
- 完成握手后會獲取Handshake數(shù)據(jù),執(zhí)行到這里說明握手已經(jīng)成功了,服務(wù)器的證書已經(jīng)被信任了。證實的信息就在Handshake中。
通過我們傳域名檢測完成域名檢測,也就是hostnameVerifier
類,調(diào)用它的verify
方法,通過返回的boolean值,進行判斷。默認的值時OkHostnameVerifier
。verify
方法實現(xiàn)如下。這里檢測了host和ip的值。如果不一致,可能證書被替換了。
public boolean verify(String host, X509Certificate certificate) { return verifyAsIpAddress(host) ? verifyIpAddress(host, certificate) : verifyHostname(host, certificate); }
- 通過
CertificatePinner
固定證書檢測,調(diào)用check
進行檢測。如果當前受信的證書不滿足固定的配置,那么就不能繼續(xù)請求。固定證書的威力很大,如果配置了,那么后續(xù)的版本必須滿足這個固定的配置,所以一直要商量好。 - 所有的檢查通過,握手成功。這時就是獲取配置的時候了。比如商議的Http版本和連接成功的輸入輸出流,之后的傳輸,也會通過
SSlSocket
的輸入輸出進行配置了。 以上就完成了SSL的握手和配置。
在實際應用中我們可能需要配置自己的證書,如果完全使用CA的證書,我們是不需要配置什么的,使用默認配置即可,但是還是有些場景需要自己動手配置Https。最常見的情形就是配置自簽名的證書,服務(wù)器給我們一個根證書,我們配置在本地,在握手階段,服務(wù)器給出的證書,會受這個根證書的認證。這樣既完成了自簽名證書的配置。下面是一些場景和常用的OkHttp的代碼配置。
配置自簽名證書
信任所有證書
這是一種非常不安全的配置,這么配置,會導致毫無安全性可言。但是有些場景還是可以暫時使用的。
static class HttpsTrustAllCertsTrustManager implements X509TrustManager { @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; //返回長度為0的數(shù)組,相當于return null } public static SSLSocketFactory createSSLSocketFactory() { SSLSocketFactory sSLSocketFactory = null; try { SSLContext sc = Platform.get().getSSLContext(); sc.init(null, new TrustManager[]{new HttpsTrustAllCertsTrustManager()},new SecureRandom()); sSLSocketFactory = sc.getSocketFactory(); } catch (Exception e) { } return sSLSocketFactory; } } static class TrustAllHostnameVerifier implements HostnameVerifier { @Override public boolean verify(String s, SSLSession sslSession) { return true; } } //構(gòu)建OkHttpClient OkHttpClient mClient = new OkHttpClient.Builder() .sslSocketFactory(HttpsTrustAllCertsTrustManager .createSSLSocketFactory(), new HttpsTrustAllCertsTrustManager()) .hostnameVerifier(new TrustAllHostnameVerifier()) .build();
上面共配置了兩個變量,SslSocketFactory和HostnameVerifier。
- 第一個變量依賴X509TrustManager。這個認證中心,我們需要給一個空實現(xiàn),這樣就會信任所有的證書,創(chuàng)建的模式和OkHttpClient創(chuàng)建默認的配置套路一樣。
- 第二個HostnameVerifier,如果我們不進行配置,會走一個默認的
OkHostnameVerifier
,如果不設(shè)置也會驗證域名。所以還需要實現(xiàn)一個自定義的驗證期,永遠返回true。
這樣經(jīng)過兩個兩步的設(shè)置,就完成了所有證書的配置工作。這種模式可以配合固定證書使用,也就是服務(wù)器的證書只能滿足固定的規(guī)則才可以,也不失是一種策略。
配置自簽名證書
對于自簽名的證書,一般都是一個根證書,服務(wù)器返回的證書,使用這個根證書就可以進行認證。我們的任務(wù)就是配置這個默認的自簽名證書進入OkHttp的配置。
try { CertificateFactory cf = CertificateFactory.getInstance("X.509"); //獲取證書輸入流 InputStream caInput = null; Certificate ca; try { ca = cf.generateCertificate(caInput); } finally { caInput.close(); } // 創(chuàng)建KeyStore,穿入證書 String keyStoreType = KeyStore.getDefaultType(); KeyStore keyStore = KeyStore.getInstance(keyStoreType); keyStore.load(null, null); keyStore.setCertificateEntry("ca", ca); // 創(chuàng)建TrustManagerFactory,用于生成TrustManager TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(keyStore); SSLContext s = SSLContext.getInstance("TLSv1", "AndroidOpenSSL"); s.init(null, tmf.getTrustManagers(), null); return s.getSocketFactory(); } catch (Exception e) { e.printStackTrace(); }
上面信任所有證書,我們只是自己實現(xiàn)了一個TrustManager,但是在配置自簽名證書的時候,就需要通過TrustManagerFactory獲取了。和上面配置的主要區(qū)別,也在于TrustManager的創(chuàng)建。
- 獲取證書的輸入流,構(gòu)建Certificate
- 獲取KeyStore,通過傳入證書Certificate
- 創(chuàng)建TrustManagerFactory,并調(diào)用init,初始化KeyStore
- 通過SSLContext的init方法獲取SSLSocketFactory
通過傳入的SSLSocketFactory,傳入OkHttpClient就可以了。整體邏輯還是比較簡單的。
以上就是Android OKHttp源碼解析Https安全處理的詳細內(nèi)容,更多關(guān)于Android OKHttp Https安全處理的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android Flutter實現(xiàn)GIF動畫效果的方法詳解
如果我們想對某個組件實現(xiàn)一組動效應該怎么辦呢?本文將利用Android Flutter實現(xiàn)GIF動畫效果,文中的示例代碼講解詳細,需要的可以參考一下2022-06-06Android上傳多張圖片的實例代碼(RxJava異步分發(fā))
本篇文章主要介紹了Android上傳多張圖片的實例代碼(RxJava異步分發(fā)),具有一定的參考價值,有興趣的可以了解一下2017-08-08Android圖片翻轉(zhuǎn)動畫簡易實現(xiàn)代碼
Android圖片翻轉(zhuǎn)動畫效果如何實現(xiàn),本文將給你一個驚喜,實現(xiàn)代碼已經(jīng)列出,需要的朋友可以參考下2012-11-11Android中使用GridView進行應用程序UI布局的教程
GridView即平常我們見到的類似九宮格的矩陣型布局,只不過默認不帶分割線,這里我們就從基礎(chǔ)開始來看一下Android中使用GridView進行應用程序UI布局的教程2016-06-06