溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

android下使用https協(xié)議發(fā)請(qǐng)求

發(fā)布時(shí)間:2020-07-24 20:01:56 來(lái)源:網(wǎng)絡(luò) 閱讀:1277 作者:weigq811202 欄目:移動(dòng)開發(fā)

Android用Java開發(fā),Java自帶的http API有HttpURLConnection,Android系統(tǒng)又加上了Apache Httpclient,后來(lái)在22版本中HttpClient又被Google刪除,所以我們不使用HttpClient來(lái)做網(wǎng)絡(luò)請(qǐng)求了,這里只給出HttpURLConnection的方式。
原生的寫法理解的沒(méi)問(wèn)題了,用第三方的寫法也好弄.這里就不寫了,有需要的同學(xué)聯(lián)系我哈.我再補(bǔ)充

在講android連接https的請(qǐng)求之前,其實(shí)應(yīng)該先學(xué)習(xí)一下https的知識(shí).https是另一種協(xié)議,跟http類似,也是發(fā)一次請(qǐng)求request建立一次鏈接connection帶回一次信息response后再把鏈接斷開.但又增加了新的內(nèi)容:在發(fā)送請(qǐng)求前,要先把數(shù)據(jù)用SSL加密,而接收的信息也是服務(wù)端用SSL加密后的,需要先解密后才能正常使用.這樣就確保了有人即便在網(wǎng)絡(luò)上抓包,也無(wú)法知道到底傳輸?shù)臄?shù)據(jù)是什么,因?yàn)閯e人不知道你們的密鑰是什么,比較安全.那有人就說(shuō)了,客戶端client怎么和服務(wù)端server商定一個(gè)只有雙方知道的密鑰呢?啊,能這樣想就證明你已經(jīng)對(duì)HTTPS的SSL加密有一些認(rèn)識(shí)了.其實(shí)過(guò)程也簡(jiǎn)單.一般來(lái)說(shuō)服務(wù)端server都是些網(wǎng)站,都是任何人都能訪問(wèn)的,但客戶端又得得到一個(gè)只有自己和server知道而其它c(diǎn)lient不知道的密鑰.其實(shí)這步也不難啊,只要client第一次訪問(wèn)server時(shí),server象管理session一樣給它一個(gè)唯一字符串,以后雙方都用這個(gè)做密鑰就好了嘛.
有了上一步的想法,好象HTTPS也很好理解,但是,人家HTTPS想的事情比這個(gè)要多.人家是這樣想的:在做某些事情之前客戶端client必須要先信任這個(gè)server不是仿冒的才跟它通信.也就是說(shuō)有些事情是不能在釣魚網(wǎng)站(仿冒的網(wǎng)站,就算你搞了DNS進(jìn)攻讓別人比如支付寶的域名指向你的服務(wù)器)上做的.這一步又是如何完成的呢?其實(shí)是客戶端要先有服務(wù)端的一個(gè)簽名文件(有時(shí)又叫指紋信息),也就是CA證書.終于說(shuō)到服務(wù)端的CA證書了,好了,下面說(shuō)對(duì)我們這次工作有用的東西,有關(guān)HTTPS和SSL的更多知識(shí),大家可以去參考百度百科.
服務(wù)端用的CA證書,其實(shí)分為兩種,一:花了錢向一個(gè)什么中心申請(qǐng)注冊(cè)的,另一種是自己用工具生成一個(gè)而不去花錢注冊(cè).
第一種,就象百度這樣的,我們可以直接象用HTTP一樣是去這樣的HTTPS的鏈接.因?yàn)檫@樣的,你的connection會(huì)自動(dòng)從注冊(cè)中心下載證書并配置.大網(wǎng)站一般都這樣.
第二種,就需要做處理.要做的處理寫下面.

處理如下:
先跟服務(wù)端要一個(gè)證書文件,然后通過(guò)一大段代碼設(shè)置到我們的HttpURLConnection中.其實(shí)就是讓我們的client端信任此server.
((HttpsURLConnection) httpConn).setSSLSocketFactory(sslSocketFactory); //至于這個(gè)sslSocketFactory如何通過(guò)證書產(chǎn)生,哈哈.好大一段代碼,參考完整的代碼中的寫法吧.

但好象還有沒(méi)有證書的,配置就是讓HttpURLConnection相信一個(gè)沒(méi)證書的配置,然后添加信任的域名,其實(shí)可以理解為只要是域名符合我就相信啦!!靠,這client客戶端這次可以被加了dns欺騙的釣魚網(wǎng)站進(jìn)攻了...
((HttpsURLConnection) urlConnection).setSSLSocketFactory(sslSocketFactory);
((HttpsURLConnection) urlConnection).setHostnameVerifier(SSLContextUtil.hostnameVerifier);
看,多了一行吧.
經(jīng)測(cè)試,沒(méi)有證書只相信域名的這種做法,其實(shí)對(duì)那些需要證書且需要配置的網(wǎng)站,也能正常訪問(wèn).看來(lái)CA證書還真是僅僅只做了讓客戶端如何相信他啊,也就是防釣魚進(jìn)攻.

簡(jiǎn)單說(shuō)一下什么是釣魚進(jìn)攻:就是進(jìn)攻者為了得到你的支付寶賬號(hào)和密碼,就做了一個(gè)跟支付寶網(wǎng)站看上去一樣的網(wǎng)站,然后想辦法引導(dǎo)你在他的網(wǎng)站上登錄你的支付寶....這就是釣魚....
所謂的DNS進(jìn)攻,就是讓別人的正常域名不再指向別人的網(wǎng)站,比如支付寶的域名本來(lái)是指向阿里的支付寶網(wǎng)站服務(wù)器的ip的,但被進(jìn)攻成功后,就變成了指向進(jìn)攻者的釣魚網(wǎng)站的IP了..此時(shí)用戶就算檢查瀏覽器中地址欄的域名,也無(wú)法排除.
為了防止這樣的事情發(fā)生,HTTPS協(xié)議規(guī)定了客戶端在使用HTTPS之前,必須得先確認(rèn)server服務(wù)端的身份,于是引入CA證書.為了方便客戶端client去訪問(wèn)他,又引入一個(gè)什么注冊(cè)中心.

下面是我的例子的所有代碼

SSLContextUtil類,核心類.
package cn.wei.https;

import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import javax.net.ssl.TrustManagerFactory;

import android.content.Context;

public class SSLContextUtil {

private static SSLContext mSSLContext;
private static SSLContext mNoCarSSLContext;
private static HostnameVerifier hostnameVerifier = new HostnameVerifier() {@Override
br/>@Override
return true;
}
};

public static SSLContext getSSLContext() {
return mSSLContext;
}
public static SSLContext getNoCarSSLContext() {
return mNoCarSSLContext;
}
public static HostnameVerifier getHostnameVerifier(){
return hostnameVerifier;
}

public static void init(Context c) {
try {
mSSLContext = getSSLContext2(c);
} catch (Exception e) {
e.printStackTrace();
}
try {
mNoCarSSLContext = getNoCarSLLContext2();
} catch (Exception e) {
e.printStackTrace();
}
}
private static SSLContext getNoCarSLLContext2() {
// SSLContext sslContext = null;
//X509TrustManager a;//為了import這個(gè)類,就得這樣寫一下.
SSLContext sslContext = null;
try {
sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{new X509TrustManager() {@Override
br/>@Override

        @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;

}

private static SSLContext getSSLContext2(Context c)
throws NoSuchAlgorithmException, IOException, CertificateException,
KeyStoreException, UnrecoverableKeyException,
KeyManagementException {
// 生成SSLContext對(duì)象
SSLContext sslContext = SSLContext.getInstance("TLS");
// 從assets中加載證書
InputStream inStream = c.getAssets().open("srca.cer");

// 證書工廠
CertificateFactory cerFactory = CertificateFactory.getInstance("X.509");
Certificate cer = cerFactory.generateCertificate(inStream);

// 密鑰庫(kù)
KeyStore kStore = KeyStore.getInstance("PKCS12");
kStore.load(null, null);
kStore.setCertificateEntry("trust", cer);// 加載證書到密鑰庫(kù)中

// 密鑰管理器
KeyManagerFactory keyFactory = KeyManagerFactory
.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyFactory.init(kStore, null);// 加載密鑰庫(kù)到管理器

// 信任管理器
TrustManagerFactory tFactory = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tFactory.init(kStore);// 加載密鑰庫(kù)到信任管理器

// 初始化
sslContext.init(keyFactory.getKeyManagers(),
tFactory.getTrustManagers(), new SecureRandom());
return sslContext;
}

}

Application類,輔助初始化的

public class MyApp extends Application {

@Override
public void onCreate() {
super.onCreate();
SSLContextUtil.init(this);
}
}

Activity類,使用的.

package cn.wei.https;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends Activity {
TextView tv_html;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_html = (TextView) this.findViewById(R.id.tv_html);

AsyncTask<String, String, String> at = new AsyncTask<String, String, String>() {

@Override
protected String doInBackground(String... params) {
HttpURLConnection httpConn = null;
try {
URL url = new URL(params[0]);
URLConnection conn = url.openConnection();
httpConn = (HttpURLConnection) conn;
// 設(shè)置SSLSocketFoactory,這里有兩種:1.需要安全證書 2.不需要安全證書;看官且往下看
if (httpConn instanceof HttpsURLConnection) { // 是Https請(qǐng)求
// 0.需要證書但不需要配的.什么也不用寫.比如百度的https://www.baidu.com
// 1.需要安全證書且需要配的.
// SSLContext sslContext = SSLContextUtil.getSSLContext();
// if (sslContext != null) {
// SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
// ((HttpsURLConnection) httpConn).setSSLSocketFactory(sslSocketFactory);
//
//
// }
// 2.不需要安全證書但需要配的:server端有但沒(méi)給,client端配置直接相信此域名.
// SSLContext sslContext = SSLContextUtil.getNoCarSSLContext();
// if (sslContext != null) {
// SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
// ((HttpsURLConnection) httpConn).setSSLSocketFactory(sslSocketFactory);
// ((HttpsURLConnection) httpConn).setHostnameVerifier(SSLContextUtil.getHostnameVerifier());
// }
}
httpConn.setRequestMethod("GET");
httpConn.setReadTimeout(16000);
httpConn.setConnectTimeout(16000);
int resCode = httpConn.getResponseCode();
if (resCode == 200) {
try (InputStream in = httpConn.getInputStream();
Reader r = new InputStreamReader(in, "UTF-8");
BufferedReader br = new BufferedReader(r);) {
String line = null;
StringBuilder sb = new StringBuilder();
do {
line = br.readLine();
sb.append(line).append("\n");
} while (line != null);
return sb.toString();
} catch (IOException e) {
throw e;
}
} else {
return "網(wǎng)絡(luò)請(qǐng)求錯(cuò)誤.resCode:" + resCode;
}
} catch (MalformedURLException e) {
e.printStackTrace();
return "err:" + e.getMessage();
} catch (IOException e) {
e.printStackTrace();
return "err:" + e.getMessage();
} finally {
httpConn.disconnect();
}

}

@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
tv_html.setText(result);

}

};
//at.execute("https://kyfw.12306.cn/otn/");//這個(gè)是有證書需要配的.
//at.execute("https://www.baidu.com");//百度是有證書但不用配的.
at.execute("https://www.alipay.com/");//有證書但不用配的.

}

}

.

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI