关于Retrofit使用HTTPS的相关问题

来源:互联网 发布:mysql choose when 编辑:程序博客网 时间:2024/05/16 06:42

先贴一个Google官方对https和ssl的说明:
https://developer.android.com/training/articles/security-ssl.html
首先说为什么使用https,简单点说就是为了防止数据传输过程中信息被窃取或偷换。防止中间人攻击。
分两种情况来说:

一、服务器使用了知名CA发放的证书

从 Android 4.2 (Jelly Bean) 开始,Android 目前包含在每个版本中更新的 100 多个 知名CA。CA 具有一个证书和一个私钥,这点与服务器相似。为服务器发放证书时,CA 使用其私钥签署服务器证书。然后,客户端可以验证该服务器是否具有平台已知的 CA 发放的证书。
假设有一个由知名 CA 发放证书的网络服务器,那么,可以使用直接使用retrofit即可发起安全的请求。对于验证证书和主机名的细节,OKHttp 框架在 API 中已经考虑了这些细节。

二、服务器使用了未知的证书颁发机构(或自签署证书的情况)

在这种情况下,由于您具有系统不信任的 CA,将发生 SSLHandshakeException。原因可能是您有一个来自 Android 还未信任的新 CA 的证书,或您的应用在没有 CA 的较旧版本上运行。CA 未知的原因通常是因为它不是公共 CA,而是政府、公司或教育机构等组织发放的仅供自己使用的私有 CA。
此过程可能有点复杂,下面的示例展示了这个过程,从 InputStream 获取一个特定的 CA,用该 CA 创建 KeyStore,然后用后者创建和初始化 TrustManager。TrustManager 是系统用于从服务器验证证书的工具,可以使用一个或多个 CA 从 KeyStore 创建,而创建的 TrustManager 将仅信任这些 CA。
如果是新的 TrustManager,此示例将初始化一个新的 SSLContext,后者可以提供一个 SSLSocketFactory,您可以通过 OkHttpClient添加socketFactory(SSLSocketFactory)。这样一来,连接将使用您的 CA 验证证书。
具体步骤如下:
1. 使用命令行获得服务器的数字证书。
echo -n | openssl s_client -connect api.abc.com:443 | sed -ne ‘/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p’ > server.cert
注意粗体内容要分别替换成你的服务器地址和要保存到本地的数字证书文件名称。
2. 转化数字证书为BKS格式
我们知道Java本身支持的证书格式jks,但是遗憾的是在android当中并不支持jks格式正式,而是需要bks格式的证书。因此我们需要将jks证书转换成bks格式证书。
首先要下载bouncycastle 的JAR,这是目前的最新版:
http://repo2.maven.org/maven2/org/bouncycastle/bcprov-jdk16/1.46/bcprov-jdk16-1.46.jar
执行以下命令进行转换:
keytool -importcert -v -trustcacerts -file “server.cert” -alias server_alias -keystore “server.bks” -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath “bcprov-jdk16-146.jar” -storetype BKS -storepass bkspassword

同样注意黑体字部分是你需要修改的。
将生成好的server.bks拷贝到android工程的res/raw目录
开始代码:

public static SSLSocketFactory getSSLSocketFactory(Context context){       try {           KeyStore ksTrust = KeyStore.getInstance("BKS");           InputStream instream = context.getResources()           .openRawResource(R.raw.server);           ksTrust.load(instream, "bkspassword".toCharArray());         //TrustManager decides which certificate authorities to use.           TrustManagerFactory tmf = TrustManagerFactory  .getInstance("X509");//TrustManagerFactory.getDefaultAlgorithm()           tmf.init(ksTrust);           SSLContext sslContext = SSLContext.getInstance("TLS");           sslContext.init(null, tmf.getTrustManagers(), null);           return  sslContext.getSocketFactory();       } catch (KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException | KeyManagementException e) {           e.printStackTrace();       }       return null;   }

然后在初始化retrofit的时候把SSLSocketFactory加进去

okHttpClient = new OkHttpClient.Builder()                .addInterceptor(httpLoggingInterceptor)                .socketFactory(sslSocketFactory)                .build();
0 0
原创粉丝点击