1. 程式人生 > >android 使用https請求請求資料

android 使用https請求請求資料

android 使用https請求

今年年初就已經吵吵著要把大部分的服務端由http轉成https了,但是由於很多公司還是比較懶,而且有的公司可能不想再多掏一些錢去對自己的網址加入CA認證,所以這件事就一直拖下來了,但是隨著使用者資料越來越多暴露在一些不法分子眼前,所以資訊保安越來越被使用者重視,一些金融、貸款公司已經開始使用這種技術了,今天就來講解一下android上面的通過https對伺服器進行請求。

首先先來解答一下疑惑,我們在做測試的時候經常會對https://www.baidu.com或者https://www.github.com進行一個網路工具類的測試,但是不知道大家有沒有注意到,這些網址連結之前全都是https://的,為什麼我們在訪問的時候完全沒有報錯,也能夠正常的訪問呢。ok,其實這兩個大網站已經被CA認證過了,而CA證書已經被android裝置預設支援了,所以這些CA認證的網站可以直接通過HttpUrlConnection進行連線,當然也可以通過HttpsUrlConnection進行連線。

但是除了被CA認證的網址就不能夠正常的連線了,比如我們訪問神奇的網站12306時,在他的註冊頁面其實已經升級成了Https協議的了,而且這個網站的證書是沒有被CA認證過的。我們來分別對比下百度的 和github 還有我們神奇的網站12306的 簽名檔案~~~

見圖:

第一張是百度網站的 證書檔案資訊

這張是github的證書資訊

這張當然就是12306的嘍

大家可以自己開啟電腦瀏覽器,開啟開發者工具(或者F12),然後點選security就能看到這個資訊了,如果對證書感興趣,還可以點選上邊的“view certificate”去檢視證書的資訊

我們通過上面的三個圖,不難分析出baidu 和github使用的是CA的認證的證書,而12306並沒有,12306用的是自己證書

這就導致了12306需要我們特別去寫一下網路請求,而百度和github則不需要。

那我們怎麼去正常的訪問12306呢,這裡我封裝了一個網路請求類,核心程式碼在這裡:

try {

URL url = new URL(path);

//1.改成s

HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();

//2.SSLContext 初始化

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

MyX509TrustManager myX509TrustManager = new MyX509TrustManager(getX509Certificate(context));

TrustManager[] trustManagers={myX509TrustManager};

tls.init(null,trustManagers,new SecureRandom());

//3.ssl工廠

SSLSocketFactory factory = tls.getSocketFactory();

//4.新增一個主機名稱校驗器

conn.setHostnameVerifier(new HostnameVerifier() {

@Override

public boolean verify(String hostname, SSLSession session) {

if (hostname.equals("kyfw.12306.cn")) {

return true;

}else{

return false;

}

}

});

conn.setSSLSocketFactory(factory);

conn.setRequestMethod("GET");

conn.setReadTimeout(5000);

conn.setConnectTimeout(5000);

conn.connect();

InputStream inputStream = conn.getInputStream();

StringBuilder sb=new StringBuilder();

int flag;

byte[] buf=new byte[1024];

while((flag=inputStream.read(buf))!=-1){

sb.append(new String(buf,0,flag));

}

String s = sb.toString();

//呼叫對方傳入callback完成回撥操作

callBack.onSuccess(s);

} catch (Exception e) {

e.printStackTrace();

callBack.onFail(e);

}


主要的思路是:

1.先將我們常用的httpurlconnection變成HttpsConnection

2.初始化我們的SSLContext 這個類是ssl的一個幫助類,能夠幫助我們去驗證我們的證書檔案

這個環節中其實稍微多一些操作,比如獲取SSLContext的例項

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

還有建立SSLContext的初始化引數,這個MyX509TrustManager是我自己封裝的類

MyX509TrustManager myX509TrustManager = new MyX509TrustManager(getX509Certificate(context));

封裝的類如下

package com.guaju.httpsrequesttest.http;

import java.security.InvalidKeyException;

import java.security.NoSuchAlgorithmException;

import java.security.NoSuchProviderException;

import java.security.SignatureException;

import java.security.cert.CertificateException;

import java.security.cert.X509Certificate;

import javax.net.ssl.X509TrustManager;

/**

* Created by guaju on 2017/11/7.

*/

public class MyX509TrustManager implements X509TrustManager {

//如果需要對證書進行校驗,需要這裡去實現,如果不實現的話是不安全

X509Certificate mX509Certificate;

public MyX509TrustManager(X509Certificate mX509Certificate) {

this.mX509Certificate = mX509Certificate;

}

@Override

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

}

@Override

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

for (X509Certificate certificate:chain){

//檢查證書是否有效

certificate.checkValidity();

try {

certificate.verify(mX509Certificate.getPublicKey());

} catch (NoSuchAlgorithmException e) {

e.printStackTrace();

} catch (InvalidKeyException e) {

e.printStackTrace();

} catch (NoSuchProviderException e) {

e.printStackTrace();

} catch (SignatureException e) {

e.printStackTrace();

}

}

}

@Override

public X509Certificate[] getAcceptedIssuers() {

return new X509Certificate[0];

}

}

而上個類中傳入的構造方法中的證書檔案

X509Certificate mX509Certificate;

這個證書檔案需要通過我們下載的證書去獲得,12306的證書在官網首頁,而我們如果開發自己的公司的網站的話,後臺應該會給我們一份,我們拿著這個證書放到assets目錄下(或者後臺的伺服器上)就可以轉變成我們自己的簽名了,下午是12306下載證書的地方:

下方是提供的將assets中的證書檔案流轉化成證書的方法,很簡單:

//拿到自己的證書

X509Certificate getX509Certificate(Context context) throws IOException, CertificateException {

InputStream in = context.getAssets().open("srca.cer");

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

X509Certificate certificate = (X509Certificate) instance.generateCertificate(in);

return certificate;

}

建立TrustManager陣列,將上方的MyX509TrustManager放進陣列中去

TrustManager[] trustManagers={myX509TrustManager};

然後呼叫SSLContext的初始化方法

tls.init(null,trustManagers,new SecureRandom());

3.上方的sslcontext初始化好之後,我們就可以做SSLSocketFactory的建立了

SSLSocketFactory factory = tls.getSocketFactory();

然後把這個工廠為我們的連線conn設定上

conn.setSSLSocketFactory(factory);

4.新增主機名稱校驗器,記住這裡的主機名稱地址需要檢視我們的證書的配置,不能瞎寫

證書配置如下圖

下方的名稱及上方的常用名稱

conn.setHostnameVerifier(new HostnameVerifier() {
    @Override
    public boolean verify(String hostname, SSLSession session) {
            if (hostname.equals("kyfw.12306.cn")) {
            return true;
        }else{
            return false;
            }

    }
});

這樣的話就可以訪問12306的註冊頁面了。

ok,為了方便大家使用,我已經提交到github了,如果大家覺得不錯,記得star 或者fork哦 ,多謝~~~

尊重作者勞動成果: