您的位置:首页 > 理论基础 > 计算机网络

Android OkHttp实现HTTPS访问,支持Android 4.X系统HTTPS访问

2017-02-21 20:48 495 查看
版权声明:本文为博主原创文章,未经我的允许不得转载!

转载请标明出处: http://blog.csdn.net/guiying712/article/details/56301736 ,本文出自:【张华洋的博客】

许多网站都会介绍一个糟糕的替代解决方案,让您使用一个没用的 TrustManager。如果您这样做还不如不加密通信,因为任何人都可以在公共 WLAN 热点下,使用伪装成您的服务器的代理发送您的用户流量,通过 DNS 欺骗攻击您的用户。然后,攻击者可以记录密码和其他个人数据。此方法之所以有效是因为攻击者可以生成一个证书,且没有可以切实验证证书是否来自值得信任的来源的 TrustManager,从而使您的应用可与任何人通信。因此,不要使用不做证书校验的TrustManager,暂时性的也不行。下面是目前最完善的Https证书校验工具类,实现了服务端和客户端之间的基于身份认证的交互,并且真正实现了 TrustManger 的 checkServerTrusted() 方法,对服务器证书域名进行了强校验,另外也真正实现了 HostnameVerifier 的 verify() 方法

/**
* @param context   上下文
* @param bksFileId "XXX.bks"文件(文件位置res/raw/XXX.bks)
* @param password  The certificate's password.
* @return SSLParams
*/
public static SSLParams getSslSocketFactory(Context context, @RawRes int bksFileId, String password, String alias) {
if (context == null) {
throw new NullPointerException("context == null");
}
SSLParams sslParams = new SSLParams();
try {
// 创建一个BKS类型的KeyStore,存储我们信任的证书
KeyStore clientKeyStore = KeyStore.getInstance("BKS");
clientKeyStore.load(context.getResources().openRawResource(bksFileId), password.toCharArray());
//通过alias直接从密钥库中读取证书
Certificate rootCA = clientKeyStore.getCertificate(alias);
// Turn it to X509 format.
InputStream certInput = new ByteArrayInputStream(rootCA.getEncoded());
X509Certificate serverCert = (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(certInput);
//关闭流
CloseUtils.closeIO(certInput);

TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
//用我们之前的keyStore实例初始化TrustManagerFactory,这样trustManagerFactory就会信任keyStore中的证书
trustManagerFactory.init(clientKeyStore);

KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(clientKeyStore, password.toCharArray());

X509TrustManager x509TrustManager = new SafeTrustManager(serverCert);

//创建TLS类型的SSLContext对象,that uses our TrustManager
SSLContext sslContext = SSLContext.getInstance("TLS");

//用上面得到的trustManagers初始化SSLContext,这样sslContext就会信任keyStore中的证书
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());

//Android 4.X 对TLS1.1、TLS1.2的支持
sslParams.sSLSocketFactory = new Tls12SocketFactory(sslContext.getSocketFactory());
sslParams.trustManager = x509TrustManager;
return sslParams;
} catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException | UnrecoverableKeyException | IOException | CertificateException e) {
throw new AssertionError(e);
}
}


自行实现的X509TrustManager,用于对服务器证书域名进行强校验

/**
* 对服务器证书域名进行强校验
*/
private static class SafeTrustManager implements X509TrustManager {
private X509Certificate mCertificate;

private SafeTrustManager(X509Certificate serverCert) {
mCertificate = serverCert;
}

@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String authType) throws CertificateException {

}

@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String authType) throws CertificateException {
if (x509Certificates == null) {
throw new IllegalArgumentException("Check Server x509Certificates is null");
}

if (x509Certificates.length < 0) {
throw new IllegalArgumentException("Check Server x509Certificates is empty");
}

try {
for (X509Certificate cert : x509Certificates) {
// Make sure that it hasn't expired.
cert.checkValidity();
//和App预埋的证书做对比
cert.verify(mCertificate.getPublicKey());
}
} catch (NoSuchAlgorithmException | InvalidKeyException | NoSuchProviderException | SignatureException e) {
e.printStackTrace();
}
}

@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}


自定义HostnameVerifier,用于校验主机名,请把”192.168.0.10”换成你们公司的主机IP

public static HostnameVerifier getHostnameVerifier() {
return new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
if ("192.168.0.10".equals(hostname)) {
return true;
} else {
HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
return hv.verify(hostname, session);
}
}
};
}


自定义SSLSocketFactory ,实现Android 4.X 对TLSv1.1、TLSv1.2的支持

private static class Tls12SocketFactory extends SSLSocketFactory {

private static final String[] TLS_SUPPORT_VERSION = {"TLSv1.1", "TLSv1.2"};

final SSLSocketFactory delegate;

private Tls12SocketFactory(SSLSocketFactory base) {
this.delegate = base;
}

@Override
public String[] getDefaultCipherSuites() {
return delegate.getDefaultCipherSuites();
}

@Override
public String[] getSupportedCipherSuites() {
return delegate.getSupportedCipherSuites();
}

@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
return patch(delegate.createSocket(s, host, port, autoClose));
}

@Override
public Socket createSocket(String host, int port) throws IOException {
return patch(delegate.createSocket(host, port));
}

@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
return patch(delegate.createSocket(host, port, localHost, localPort));
}

@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
return patch(delegate.createSocket(host, port));
}

@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
return patch(delegate.createSocket(address, port, localAddress, localPort));
}

private Socket patch(Socket s) {
//代理SSLSocketFactory在创建一个Socket连接的时候,会设置Socket的可用的TLS版本。
if (s instanceof SSLSocket) {
((SSLSocket) s).setEnabledProtocols(TLS_SUPPORT_VERSION);
}
return s;
}
}


这个工具的使用方法

HttpsUtils.SSLParams sslParams = HttpsUtils.getSslSocketFactory(Utils.getContext(), R.raw.bks, "66666", "6666")
okHttpClient = new OkHttpClient.Builder()
.connectTimeout(30000L, TimeUnit.MILLISECONDS)
.sslSocketFactory(sslParams.sSLSocketFactory, sslParams.trustManager)
.hostnameVerifier(HttpsUtil.getHostnameVerifier())
.addInterceptor(new LoggerInterceptor(null, true))
.build();


最后贴上,HttpsUtil源码请点击这里:HttpsUtils源码,如果你觉得对你有帮助请顺手点个star.

另外这是我写的Android项目组件化详细实施方案 ,欢迎大家提意见。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: