android https请求证书过滤白名单,Android处理https请求的证书问题
android中對部分站點發送https請求會報錯,原因是該站點的證書時自定義的,而非官方的,android手機不信任其證書,為了解決這個問題,一般有兩種解決方案
忽略證書驗證
下載證書到本地,添加到信任證書列表
在android中我們訪問網絡一般有兩種方式,一種是使用httpURLConnection,一種是使用httpClient。這里先講前者,然后再講解后者。順便會講解在volley框架中如何使用https。
一,HttpURLConnection訪問https站點
1,忽略證書
如果要忽略證書的驗證,我們只需提供一個HostnameVerifier和X509TrustManager的空實現,如下代碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78public void requestWithoutCA() {
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, new TrustManager[] { new MyTrustManager() },
new SecureRandom());
HttpsURLConnection
.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection
.setDefaultHostnameVerifier(new MyHostnameVerifier());
URL url = new URL("https://certs.cac.washington.edu/CAtest/");
HttpURLConnection urlConnection = (HttpURLConnection) url
.openConnection();
InputStream in = urlConnection.getInputStream();
// 取得輸入流,并使用Reader讀取
BufferedReader reader = new BufferedReader(
new InputStreamReader(in));
System.out.println("=============================");
System.out.println("Contents of get request");
System.out.println("=============================");
String lines;
while ((lines = reader.readLine()) != null) {
System.out.println(lines);
}
reader.close();
// 斷開連接
urlConnection.disconnect();
System.out.println("=============================");
System.out.println("Contents of get request ends");
System.out.println("=============================");
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (KeyManagementException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private class MyHostnameVerifier implements HostnameVerifier {
@Override
public boolean verify(String hostname, SSLSession session) {
// TODO Auto-generated method stub
return true;
}
}
private class MyTrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
// TODO Auto-generated method stub
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
// TODO Auto-generated method stub
}
@Override
public X509Certificate[] getAcceptedIssuers() {
// TODO Auto-generated method stub
return null;
}
}
2,使用證書
該代碼時訪問華盛頓大學的一個網頁,證書可以到以下鏈接下載:
代碼如下:
注意,此處使用的是HttpsURLConnection,而非HttpURLConnection。
下面的代碼,加載證書等等操作,最終都是為了setSSLSocketFactory這一步。
public void requestByHttps() {
try {
// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// From
// https://www.washington.edu/itconnect/security/ca/load-der.crt
InputStream caInput = this.getAssets().open("load_der.crt");
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
System.out.println("ca="
+ ((X509Certificate) ca).getSubjectDN());
} finally {
caInput.close();
}
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
URL url = new URL("https://certs.cac.washington.edu/CAtest/");
HttpsURLConnection urlConnection = (HttpsURLConnection) url
.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
InputStream in = urlConnection.getInputStream();
// 取得輸入流,并使用Reader讀取
BufferedReader reader = new BufferedReader(
new InputStreamReader(in));
System.out.println("=============================");
System.out.println("Contents of get request");
System.out.println("=============================");
String lines;
while ((lines = reader.readLine()) != null) {
System.out.println(lines);
// tv.setText(tv.getText().toString() + lines);
}
reader.close();
// 斷開連接
urlConnection.disconnect();
System.out.println("=============================");
System.out.println("Contents of get request ends");
System.out.println("=============================");
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (KeyManagementException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (KeyStoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (CertificateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
3, Volley中使用HttpURLConnection訪問https
Volley中使用HttpURLConnection訪問網絡時,是由HurlStack類處理,該類的幾個構造方法如下:
public HurlStack() {
this(null);
}
/**
* @param urlRewriter Rewriter to use for request URLs
*/
public HurlStack(UrlRewriter urlRewriter) {
this(urlRewriter, null);
}
/**
* @param urlRewriter Rewriter to use for request URLs
* @param sslSocketFactory SSL factory to use for HTTPS connections
*/
public HurlStack(UrlRewriter urlRewriter, SSLSocketFactory sslSocketFactory) {
mUrlRewriter = urlRewriter;
mSslSocketFactory = sslSocketFactory;
}
打開連接的方法如下,注意其中也有上面提到的的setSSLSocketFactory方法。
結合構造方法以及以下的代碼,不難理解,為了訪問https,只需奧在構建HurlStack時,傳入一個已經設置了證書的SLSocketFactory即可,設置代碼和上面的代碼類似。
private HttpURLConnection openConnection(URL url, Request> request) throws IOException {
HttpURLConnection connection = createConnection(url);
int timeoutMs = request.getTimeoutMs();
connection.setConnectTimeout(timeoutMs);
connection.setReadTimeout(timeoutMs);
connection.setUseCaches(false);
connection.setDoInput(true);
// use caller-provided custom SslSocketFactory, if any, for HTTPS
if ("https".equals(url.getProtocol()) && mSslSocketFactory != null) {
((HttpsURLConnection)connection).setSSLSocketFactory(mSslSocketFactory);
}
return connection;
}
二,使用httpClient訪問https站點
1,忽略證書
public class HttpClientHelper {
private static HttpClient httpClient;
private HttpClientHelper() {
}
public static synchronized HttpClient getHttpClient() {
if (null == httpClient) {
// 初始化工作
try {
KeyStore trustStore = KeyStore.getInstance(KeyStore
.getDefaultType());
trustStore.load(null, null);
SSLSocketFactory sf = new SSLSocketFactoryEx(trustStore);
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); //允許所有主機的驗證
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params,
HTTP.DEFAULT_CONTENT_CHARSET);
HttpProtocolParams.setUseExpectContinue(params, true);
// 設置連接管理器的超時
ConnManagerParams.setTimeout(params, 10000);
// 設置連接超時
HttpConnectionParams.setConnectionTimeout(params, 10000);
// 設置socket超時
HttpConnectionParams.setSoTimeout(params, 10000);
// 設置http https支持
SchemeRegistry schReg = new SchemeRegistry();
schReg.register(new Scheme("http", PlainSocketFactory
.getSocketFactory(), 80));
schReg.register(new Scheme("https", sf, 443));
ClientConnectionManager conManager = new ThreadSafeClientConnManager(
params, schReg);
httpClient = new DefaultHttpClient(conManager, params);
} catch (Exception e) {
e.printStackTrace();
return new DefaultHttpClient();
}
}
return httpClient;
}
}
class SSLSocketFactoryEx extends SSLSocketFactory {
SSLContext sslContext = SSLContext.getInstance("TLS");
public SSLSocketFactoryEx(KeyStore truststore)
throws NoSuchAlgorithmException, KeyManagementException,
KeyStoreException, UnrecoverableKeyException {
super(truststore);
TrustManager tm = new X509TrustManager() {
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] chain, String authType)
throws java.security.cert.CertificateException {
}
@Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] chain, String authType)
throws java.security.cert.CertificateException {
}
};
sslContext.init(null, new TrustManager[] { tm }, null);
}
@Override
public Socket createSocket(Socket socket, String host, int port,
boolean autoClose) throws IOException, UnknownHostException {
return sslContext.getSocketFactory().createSocket(socket, host, port,
autoClose);
}
@Override
public Socket createSocket() throws IOException {
return sslContext.getSocketFactory().createSocket();
}
}
2,使用證書
AssetManager am = context.getAssets();
InputStream ins = am.open("robusoft.cer");
try {
//讀取證書
CertificateFactory cerFactory = CertificateFactory.getInstance("X.509"); //問1
Certificate cer = cerFactory.generateCertificate(ins);
//創建一個證書庫,并將證書導入證書庫
KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC"); //問2
keyStore.load(null, null);
keyStore.setCertificateEntry("trust", cer);
return keyStore;
} finally {
ins.close();
}
//把咱的證書庫作為信任證書庫
SSLSocketFactory socketFactory = new SSLSocketFactory(keystore);
Scheme sch = new Scheme("https", socketFactory, 443);
//完工
HttpClient mHttpClient = new DefaultHttpClient();
mHttpClient.getConnectionManager().getSchemeRegistry().register(sch);
//接下來這個httpclient就可以用語https請求了。
3,Volley中使用httpClient訪問https
Volley使用HttpCLient訪問網絡是借助HttpClientStack類,其中的構造方法不同于HurlStack那么多,而只有一個
public HttpClientStack(HttpClient client) {
mClient = client;
}
很簡單,我們只需要在構造HttpClientStack時傳入一個已經設置了證書的HttpClient,按照上面講述的那樣設置即可。
總結
以上是生活随笔為你收集整理的android https请求证书过滤白名单,Android处理https请求的证书问题的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: javascript判断浏览器当前运行环
 - 下一篇: Qt 信号和槽