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,按照上面讲述的那样设置即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值