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

客户端认证自签名HTTPS证书

2015-12-15 16:16 701 查看
  在最近的项目中,与某服务器连接的请求采用的是https协议,但是该服务器的证书又不是经过权威机构认证的证书,因此采用普通的方式直接连接是不行。本文给出解决方案。

  HTTPS是HTTP之下、TCP之上的安全密码层,可以使用SSL或TSL,本文用SSL来描述SSL或TSL。大部分困难的编码和解码工作都在SSL中完成了,客户端和服务器端在使用HTTPS进行通信的时候不需要实现复杂的加解密算法之类的。SSL使用证书来创建安全连接,一般有两种验证方式。第一种是客户端认证服务器端的提供的证书,一般的HTTPS网站都采用这种方式。第二种是客户端和服务器端都要认证对方的证书,一般是APP应用和它的服务器可能会采用这样的方式。本文说的就是第一种情况,并且当该服务器的证书不是权威机构认证的证书(一般是为了省钱。。。因为权威机构认证的证书可不便宜。。。)。

  以Android客户端为例,在目前最新的SDK 23中,已经完全移除了HttpClient,所有的网络请求均要采用HttpUrlConnection来实现。那么对于这种自签名的证书,HttpUrlConnection其实只需要多设置一个属性就可以了,其实就是setSSLSocketFactory()方法就可以了。SSLSocketFactory这个类在我的理解就是这一次HTTPS连接SSL层的抽象,并且这个类是通过SSLContext的getSocketFactory()来得到。那么问题就变成了如何去构造SSLContext就可以了。

  SSLContext只需要通过以下代码就可以实例化。

SSLContext sslContext = SSLContext.getInstance("SSL");
ssl.init(null, null, null);


  注意到init方法的第二个参数传递是TrustManager的数组。那么问题就在于如何使用服务器提供的证书去生成TrustManager数组了。直接上代码,在Android里,将证书放到asset目录中,通过AssetManager读取它。

public static TrustManager[] getTrustManagers(Context cxt) {
InputStream caInput = null;
try {
caInput = new BufferedInputStream(
cxt.getResources().getAssets().open("srca.cer"));
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate ca = cf.generateCertificate(caInput);

String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);

String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);

return tmf.getTrustManagers();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (caInput != null) caInput.close();
}
return getTrustAnyManager();
}

public static TrustManager[] getTrustAnyManager() {
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;
}
};
return new TrustManager[]{tm};
}


  以上就是具体的代码实现。第二个getTrustAnyManager方法提供的是一个信任任意证书的TrustManager数组,会有安全性问题。只有当第一个方法发生异常的时候才调用第二个方法。

  经过以上方法,就可以获得一个SSLContext,只需要判断如果connection对象是HttpsUrlConnect的话,调用connection.setSocketFactory(sslContext.getSocketFactory()) 就可以了.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ssl Android HTTPS