Android如何使用Https

來源:互聯網
上載者:User

標籤:sre   mod   gets   cep   def   目標   sdk   factory   部落格   

Android如何使用Https,這一篇文章是NoHttp系列中比較重要的,為大家介紹一下內容。

什麼是Https?

HTTPS(全稱:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全為目標的HTTP通道,簡單講是HTTP的安全版。即HTTP下加入SSL層,HTTPS的安全基礎是SSL,因此加密的詳細內容就需要SSL。它是一個URI Scheme(抽象標識符體系),句法類同Http:體系。用於安全的HTTP資料轉送。Https:URL表明它使用了HTTP,但HTTPS存在不同於HTTP的預設連接埠及一個加密/身分識別驗證層(在HTTP與TCP之間)。這個系統的最初研發由網景公司(NetScape)進行,並內建於其瀏覽器Netscape Navigator中,提供了身分識別驗證與加密通訊方法。現在它被廣泛用於全球資訊網上安全敏感的通訊,例如金融、網購等涉及支付的領域。

這次不裝逼,我們來個深入淺出,先說最原始的Https,再說架構怎麼架構怎麼一句話使用Https

Android用原始Java代碼怎麼用Https

先普及一下Android怎麼用最原始java代碼請求網路,大神請掠過。

Android用Java開發,Java內建的http API有HttpURLConnection,Android系統又加上了Apache Httpclient,加上後來HttpClient在SDK中被Google刪除,所以我們也不推薦使用HttpClient來做網路請求了,所以在這裡呢也只給列出HttpURLConnection的方式。

第一步:開啟某個地址的串連

這裡咱開啟我的部落格地址,用GET方法請求

<code><code><code>URL url = new URL("https://blog.csdn.net/yanzhenjie1003");

HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();

urlConnection.setRequestMethod("GET");</code></code></code>

第二步:判斷是Https請求,設定SSLSocketFactory

如果是Https請求,那麼做安全校正等操作,這裡設定SSLSokcetFactory,這裡有兩種方法,一種是包涵Https認證的,一種是沒有認證直接允許Https請求的,而認證不認證就是從SSLContext中來的:

<code><code><code><code><code>// 設定SSLSocketFoactory,這裡有兩種:1.需要安全性憑證 2.不需要安全性憑證;看官且往下看

if (urlConnection instanceof HttpsURLConnection) { // 是Https請求

SSLContext sslContext = SSLContextUtil.getSSLContext();

if (sslContext != null) {

SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

((HttpsURLConnection) urlConnection).setSSLSocketFactory(sslSocketFactory);

}

}</code></code></code></code></code>

那麼SSLContext怎麼產生呢,哈哈先不急,咱們先把這個請求的流程走完,認證的載入往後邊看哦。

第三步:設定必要屬性

<code><code><code><code><code><code>// 設定屬性

urlConnection.setConnectTimeout(8 * 1000);

urlConnection.setReadTimeout(8 * 1000);</code></code></code></code></code></code>

第四步:讀取資料,發送到主線程,中斷連線

<code><code><code><code><code><code>int responseCode = urlConnection.getResponseCode();

if (responseCode == 200) { // 請求成功

InputStream inputStream = urlConnection.getInputStream();

// 讀取結果,發送到主線程

...

inputStream.close();

}

urlConnection.disconnect();</code></code></code></code></code></code>

完整代碼

<code><code><code><code><code><code>URL url = new URL("https://blog.csdn.net/yanzhenjie1003");

HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();

urlConnection.setRequestMethod("GET");

// 設定SSLSocketFoactory,這裡有兩種:1.需要安全性憑證 2.不需要安全性憑證;看官且往下看

if (urlConnection instanceof HttpsURLConnection) { // 是Https請求

SSLContext sslContext = SSLContextUtil.getSSLContext();

if (sslContext != null) {

SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

((HttpsURLConnection) urlConnection).setSSLSocketFactory(sslSocketFactory);

}

}

// 設定屬性

urlConnection.setConnectTimeout(8 * 1000);

urlConnection.setReadTimeout(8 * 1000);

int responseCode = urlConnection.getResponseCode();

if (responseCode == 200) { // 請求成功

InputStream inputStream = urlConnection.getInputStream();

// 讀取結果,發送到主線程

...

inputStream.close();

}

urlConnection.disconnect();</code></code></code></code></code></code>

這樣就完成整個請求,其實Android請求網路就這麼點代碼,然後我們再寫完善一點,然後封裝寫參數,容錯什麼的,就是一個小架構啦。是不是很簡單呢?

使用流行架構NoHttp怎麼玩Https

用NoHttp不要太簡單,什麼傳參數、傳檔案、下載之類的,基本都是一兩句話就搞定。

<code><code><code><code><code><code>Request<string> request = NoHttp.createStringRequest(url, RequestMethod.POST);

// 注意這裡設定SSLSokcetFactory的代碼是相同的

SSLContext sslContext = SSLContextUtil.getSSLContext();

if (sslContext != null) {

SSLSocketFactory socketFactory = sslContext.getSocketFactory();

httpsRequest.setSSLSocketFactory(socketFactory);

requestQueue.add(0, request, httpListener);// 添加到請求隊列,等待接受結果

}

</string></code></code></code></code></code></code>

我們注意到上面設定Socket的代碼是相同的,剩下的就是一句話new一個請求對象就完事。是不是比原生的還要簡單啊?

這個架構叫NoHttp,是一個Android開源網路架構。

SSLSocketFactory對象怎麼來

上面不論是純Android代碼還是NoHttp架構都用到了SSLContext,這傢伙呢就是負責認證管理和信任管理器的,我們說Https可以有認證也可以沒有認證,我們來看這兩種情況。

有安全性憑證的SSLContext

我們把Https的認證放在assets目錄下,然後通過流載入:

<code><code><code><code><code><code><code>public static SSLContext getSSLContext() {

// 產生SSLContext對象

SSLContext sslContext = SSLContext.getInstance("TLS");

// 從assets中載入認證

InputStream inStream = Application.getInstance().getAssets().open("srca.cer");

// 認證工廠

CertificateFactory cerFactory = CertificateFactory.getInstance("X.509");

Certificate cer = cerFactory.generateCertificate(inStream);

// 密鑰庫

KeyStore kStore = KeyStore.getInstance("PKCS12");

kStore.load(null, null);

kStore.setCertificateEntry("trust", cer);// 載入認證到密鑰庫中

// 密鑰管理器

KeyManagerFactory keyFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());

keyFactory.init(kStore, null);// 載入密鑰庫到管理器

// 信任管理器

TrustManagerFactory tFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());

tFactory.init(kStore);// 載入密鑰庫到信任管理器

// 初始化

sslContext.init(keyFactory.getKeyManagers(), tFactory.getTrustManagers(), new SecureRandom());

return sslContext;

}</code></code></code></code></code></code></code>

需要強調的是,最後一句中的new SecureRandom()在Android4.4之前的系統中有Bug。

修複Android系統中SecureRandom的Bug

Android 4.4之前版本的Java加密架構(JCA)中使用的Apache Harmony 6.0M3及其之前版本的SecureRandom實現存在安全性漏洞,具體位於classlib/modules/security/src/main/java/common/org/apache/harmony/security/provider/crypto/SHA1PRNG_SecureRandomImpl.java檔案的engineNextBytes()方法裡。當使用者沒有提供用於產生隨機數的種子時,程式不能正確調整位移量,導致偽隨機數產生器(PRNG)產生隨機序列的過程可被預測。

But值得高興的NoHttp內部已經fix了這一bug,如果大家要自己寫架構,恐怕要寫很多代碼去修複這個問題啦,所以推薦各位看官還是使用NoHttp。

沒有安全性憑證的SSLContext

上面看到需要需要安全性憑證的產生SSLContext就可以了,然後不需要認證的請求,需要兩個對象,一個是SSLContext(上面已經解釋過了);另一個是HostnameVerifier,顧名思義就是主機名稱匹配的意思,我們看代碼。

<code><code><code><code><code><code><code><code><code><code><code><code>public static SSLContext getSLLContext() {

SSLContext sslContext = null;

try {

sslContext = SSLContext.getInstance("TLS");

sslContext.init(null, new TrustManager[]{new X509TrustManager() {

@Override

public void checkClientTrusted(X509Certificate[] chain, String authType) {}

@Override

public void checkServerTrusted(X509Certificate[] chain, String authType) {}

@Override

public X509Certificate[] getAcceptedIssuers() {

return new X509Certificate[0];

}

}}, new SecureRandom());

} catch (Exception e) {

e.printStackTrace();

}

return sslContext;

}</code></code></code></code></code></code></code></code></code></code></code></code>

就這麼簡單,只需要傳一個nullCert Manager喝一個預設的信任管理器即可。

下面再來看HostnameVerifier,既然是主機名稱校正,那我們直接通過:

<code><code><code><code><code><code><code><code><code><code><code><code><code>private static HostnameVerifier hostnameVerifier = new HostnameVerifier() {

@Override

public boolean verify(String hostname, SSLSession session) {

return true;

}

};</code></code></code></code></code></code></code></code></code></code></code></code></code>

這個怎麼用呢?Android原生代碼用法中,擷取SSLContext的方法名不一樣,多了setHostnameVerifier,其它跟有安全性憑證的使用一致:

<code><code><code><code><code><code><code><code><code><code><code><code><code><code><code>URL url = new URL("https://blog.csdn.net/yanzhenjie1003");

HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();

urlConnection.setRequestMethod("GET");

// 設定SSLSocketFoactory,這裡有兩種:1.需要安全性憑證 2.不需要安全性憑證;看官且往下看

if (urlConnection instanceof HttpsURLConnection) { // 是Https請求

SSLContext sslContext = SSLContextUtil.getSSLContext();

if (sslContext != null) {

SSLSocketFactory sslSocketFactory = sslContext.getSLLContextNoCertificate();

((HttpsURLConnection) urlConnection).setSSLSocketFactory(sslSocketFactory);

((HttpsURLConnection) urlConnection).setHostnameVerifier(SSLContextUtil.hostnameVerifier);

}

}

// 設定屬性

urlConnection.setConnectTimeout(8 * 1000);

urlConnection.setReadTimeout(8 * 1000);

int responseCode = urlConnection.getResponseCode();

if (responseCode == 200) { // 請求成功

InputStream inputStream = urlConnection.getInputStream();

// 讀取結果,發送到主線程

...

inputStream.close();

}

urlConnection.disconnect();</code></code></code></code></code></code></code></code></code></code></code></code></code></code></code>

NoHttp用法,代碼和上邊的NoHttp載入認證的一樣,多了一句setHostnameVerifier的:

<code><code><code><code><code><code><code><code><code><code><code><code><code><code><code><code>Request<string> request = NoHttp.createStringRequest(url, RequestMethod.POST);

SSLContext sslContext = SSLContextUtil.getSSLContext();

if (sslContext != null) {

SSLSocketFactory socketFactory = sslContext.getSLLContextNoCertificate();

httpsRequest.setSSLSocketFactory(socketFactory);

httpsRequest.setHostnameVerifier(SSLContextUtil.hostnameVerifier);

requestQueue.add(0, request, httpListener);// 添加到請求隊列,等待接受結果

}</string></code></code></code></code></code></code></code></code></code></code></code></code></code></code></code></code>

如果大家通讀了全文,我相信已經會使用Android的Https了吧?

技術來源:www.shuangyulin.com

Android如何使用Https

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.