Android _实现SSL解决不受信任的证书问题
Android _实现SSL解决不受信任的证书问题
介绍
背景
?
1 2 3 | URL urlConnection =
new URL(
"http://www.codeproject.com/"
);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
|
HTTPS是什么?
?
1 2 3 4 5 | URL urlConnection =
new URL(
"https://www.codeproject.com/"
);
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
InputStream in =
new BufferedInputStream(urlConnection.getInputStream());
|
回到顶部
SSL/TLS:
回到顶部
SSL/HTTPS and X.509 证书概述
回到顶部
回到顶部
TLS (SSL)中的加密
回到顶部
MITM 攻击
?
1 2 3 | URL url =
new URL(
"https://www.example.com/"
);
HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();
InputStream in = urlConnection.getInputStream();
|
回到顶部
什么是自签名证书( self-signed certicates)
为什么有人喜欢用自签名证书
?
1 2 3 4 | URL url =
new URL(
"https://www.example.com/"
);
HttpsURLConnection urlConnection = (HttpsURLConnection)
url.openConnection();
InputStream in = urlConnection.getInputStream();
|
回到顶部
回到顶部
?
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 | import org.apache.http.conn.ssl.SSLSocketFactory;
public class MySSLSocketFactory
extends SSLSocketFactory {
SSLContext sslContext = SSLContext.getInstance(
"TLS"
);
public MySSLSocketFactory(KeyStore truststore)
throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super
(truststore);
TrustManager tm =
new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null
;
}
};
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();
}
}
|
允许所有的主机名。
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
DefaultHttpClient client =
new DefaultHttpClient();
SchemeRegistry registry =
new SchemeRegistry();
SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();
socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
registry.register(
new Scheme(
"https"
, socketFactory,
443
));
SingleClientConnManager mgr =
new SingleClientConnManager(client.getParams(), registry);
DefaultHttpClient httpClient =
new DefaultHttpClient(mgr, client.getParams());
// Set verifier
HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
// Example send http request
final String url = "https:
//www.paypal.com”
HttpPost httpPost =
new HttpPost(url);
HttpResponse response = httpClient.execute(httpPost);
HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
|
?
1 | HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
|
Mixed-Mode/No SSL.
回到顶部
证书锁定
优势
缺点
回到顶部
实现的步骤
回到顶部
第1步: 创建自签名证书和.bks 文件
回到顶部
第2步
回到顶部
第3步
?
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 | import java.io.InputStream;
import java.security.KeyStore;
import android.content.Context;
public class MyHttpClient
extends DefaultHttpClient {
private static Context context;
public static void setContext(Context context) {
MyHttpClient.context = context;
}
public MyHttpClient(HttpParams params) {
super
(params);
}
public MyHttpClient(ClientConnectionManager httpConnectionManager, HttpParams params) {
super
(httpConnectionManager, params);
}
@Override
protected ClientConnectionManager createClientConnectionManager() {
SchemeRegistry registry =
new SchemeRegistry();
registry.register(
new Scheme(
"http"
, PlainSocketFactory.getSocketFactory(),
80
));
// 用我们自己定义的 SSLSocketFactory 在 ConnectionManager 中注册一个 443 端口
registry.register(
new Scheme(
"https"
, newSslSocketFactory(),
443
));
return new SingleClientConnManager(getParams(), registry);
}
private SSLSocketFactory newSslSocketFactory() {
try {
// Get an instance of the Bouncy Castle KeyStore format
KeyStore trusted = KeyStore.getInstance(
"BKS"
);
// 从资源文件中读取你自己创建的那个包含证书的 keystore 文件
InputStream in = MyHttpClient.context.getResources().openRawResource(R.raw.codeprojectssl);
//这个参数改成你的 keystore 文件名
try {
// 用 keystore 的密码跟证书初始化 trusted
trusted.load(in,
"这里是你的 keystore 密码"
.toCharArray());
}
finally {
in.close();
}
// Pass the keystore to the SSLSocketFactory. The factory is responsible
// for the verification of the server certificate.
SSLSocketFactory sf =
new SSLSocketFactory(trusted);
// Hostname verification from certificate
// http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506
sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
// 这个参数可以根据需要调整, 如果对主机名的验证不需要那么严谨, 可以将这个严谨程度调低些.
return sf;
}
catch (Exception e) {
throw new AssertionError(e);
}
}
}
|
?
1 2 3 4 5 6 | // Instantiate the custom HttpClient
DefaultHttpClient client =
new MyHttpClient(getApplicationContext());
HttpGet get =
new HttpGet(
"https://www.google.com"
);
// 以 GET 方式读取服务器返回的数据
HttpResponse getResponse = client.execute(get);
HttpEntity responseEntity = getResponse.getEntity();
|