Android 用自签名证书实现https请求

来源:互联网 发布:java 阻塞排查 编辑:程序博客网 时间:2024/05/18 11:31

Android 用自签名证书实现https请求

一.概要

为了保护用户的信息安全、保护自己的商业利益,减少攻击面,我们需要保障通信信道的安全,采用开发方便的HTTPS是比较好的方式,比用私有协议要好,省时省力。但是如果HTTPS使用不当,就很难起到应有的保护效果。例如有人为了省事选择信任所有证书的方式绕过证书的认证,这样https的作用就完全没意义了。下面我就用Android比较流行的网络框架okhttp来做使用https,包括单向认证和双向认证 

二.OpenSSL生成证书

网上很多如何生成自签名证书的资料,这里就不详细说明,大概步骤如下:1.生成私钥server.key2.生成server.crt CA根证书(公钥)3.用根证书给客户端签发证书server.cer

三.单向认证

把服务器颁发的证书server.cer放到Android的目录assets
/** * 添加证书 * */public static SSLSocketFactory getSocketFactory() {    try {        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());        keyStore.load(null);        InputStream is = mContext.getAssets().open("server.cer");        keyStore.setCertificateEntry("0", certificateFactory.generateCertificate(is));        if (is!=null){            is.close();        }        SSLContext sslContext = SSLContext.getInstance("TLS");        TrustManagerFactory trustManagerFactory =                TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());        trustManagerFactory.init(keyStore);        sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());        return sslContext.getSocketFactory();    } catch (Exception e) {        e.printStackTrace();    }    return null;}
然后mOkHttpClient.setSslSocketFactory(getSocketFactory());就这样就实现了配置okhttp的https请求另外如果后台服务器用是nginx搭建的可以先配置
ssl on;ssl_certificate ...server.crt;ssl_certificate_key ...server.key;
然后Android客户端直接使用server.crt来代替server.cer,利用nginx来认证https请求,省去了客户端到多台服务器的认证。

四.双向认证

首先对于双向证书验证,也就是说,客户端也会有个“.key文件”,服务器那边会同时有个“.cer文件”与之对应。我们已经生成了server.key和server.cer文件。接下来按照生成证书的方式,再生成一对这样的文件,我们命名为:client.key,client.cer.然后配置服务器 <Connector  其他属性与前面一致      clientAuth="true"    truststoreFile="client.cer"   /> 配置Android端:还记得我们单向认证时sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());sslContext.init的第一个参数我们传入的是null,第一个参数的类型实际上是KeyManager[] km,主要就用于管理我们客户端的key。另外我们生成的客户端client.key是jks格式的文件,java平台才能识别,Android直接用会报错:Java.io.IOException: Wrong version of key store。所有Android端要转成bks格式,可以用转换工具Portecle,网上很多资料可以参考,这里就不详说了。然后就是我们Android端的代码实现:
/** * 添加证书 * */public static SSLSocketFactory getSocketFactory() {    try {        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());        keyStore.load(null);        InputStream is = mContext.getAssets().open("server.cer");        keyStore.setCertificateEntry("0", certificateFactory.generateCertificate(is));        if (is!=null){            is.close();        }        SSLContext sslContext = SSLContext.getInstance("TLS");        TrustManagerFactory trustManagerFactory =                TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());        trustManagerFactory.init(keyStore);        //初始化keystore        KeyStore clientKeyStore = KeyStore.getInstance("BKS");        clientKeyStore.load(mContext.getAssets().open("client.bks"), "123456".toCharArray());        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());        keyManagerFactory.init(clientKeyStore, "123456".toCharArray());        sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());        return sslContext.getSocketFactory();    } catch (Exception e) {        e.printStackTrace();    }    return null;}
"123456"为证书密码

总结

由于项目需要用到https,而之前也没有接触过,花了几天搜罗了很多资料,最后找到了实践可行的的方法,现在分享出来,希望对大家有帮助,如果有理解错误的地方,请指出,谢谢!