带有证书固定的 OkHttp
OkHttp with Certificate Pinning
我的 Android 项目 (OkHttp 3.3.1) 当前使用我的 HTTPS 网络服务(我的 PC、IIS 网络服务器、Asp.Net 网络 API、自签名证书)
辅助方法:
private SSLSocketFactory getSSLSocketFactory()
throws CertificateException, KeyStoreException, IOException,
NoSuchAlgorithmException, KeyManagementException {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = getResources().openRawResource(R.raw.iis_cert);
Certificate ca = cf.generateCertificate(caInput);
caInput.close();
KeyStore keyStore = KeyStore.getInstance("BKS");
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
return sslContext.getSocketFactory();
}
private HostnameVerifier getHostnameVerifier() {
return new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
return hv.verify("BNK-PC.LOCALHOST.COM", session);
}
};
}
代码A:
OkHttpClient client = new OkHttpClient.Builder()
.sslSocketFactory(getSSLSocketFactory())
.hostnameVerifier(getHostnameVerifier())
.build();
阅读 this CertificatePinner guide 后,我的项目在添加 .certificatePinner(certificatePinner)
时也运行良好,如下所示:
代码B:
OkHttpClient client = new OkHttpClient.Builder()
.sslSocketFactory(getSSLSocketFactory())
.certificatePinner(certificatePinner)
.hostnameVerifier(getHostnameVerifier())
.build();
根据 this Wiki,证书固定提高了安全性。
但是,其实我并没有很清楚地理解这个想法。所以我的问题是,当我的应用程序仍然使用 Code A 时,我是否需要或必须使用 certificatePinner
。换句话说,代码B是否比代码A更安全?
证书固定应该有助于某些 类 攻击
- 任何 受信任的证书颁发机构被黑客攻击并为您的域生成有效证书,例如 MITM 攻击被一个有侵略性的政府。
- 您的应用 运行 在具有额外可信证书的设备上运行,例如由提供 phone.
的公司安装
我认为一般来说,如果您从两个主要 CA 颁发证书,例如verisign,你会固定到他们的签名证书而不是你自己的。这是因为您可能会例行公事地为您的服务器生成新证书。
我的 Android 项目 (OkHttp 3.3.1) 当前使用我的 HTTPS 网络服务(我的 PC、IIS 网络服务器、Asp.Net 网络 API、自签名证书)
辅助方法:
private SSLSocketFactory getSSLSocketFactory()
throws CertificateException, KeyStoreException, IOException,
NoSuchAlgorithmException, KeyManagementException {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = getResources().openRawResource(R.raw.iis_cert);
Certificate ca = cf.generateCertificate(caInput);
caInput.close();
KeyStore keyStore = KeyStore.getInstance("BKS");
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
return sslContext.getSocketFactory();
}
private HostnameVerifier getHostnameVerifier() {
return new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
return hv.verify("BNK-PC.LOCALHOST.COM", session);
}
};
}
代码A:
OkHttpClient client = new OkHttpClient.Builder()
.sslSocketFactory(getSSLSocketFactory())
.hostnameVerifier(getHostnameVerifier())
.build();
阅读 this CertificatePinner guide 后,我的项目在添加 .certificatePinner(certificatePinner)
时也运行良好,如下所示:
代码B:
OkHttpClient client = new OkHttpClient.Builder()
.sslSocketFactory(getSSLSocketFactory())
.certificatePinner(certificatePinner)
.hostnameVerifier(getHostnameVerifier())
.build();
根据 this Wiki,证书固定提高了安全性。
但是,其实我并没有很清楚地理解这个想法。所以我的问题是,当我的应用程序仍然使用 Code A 时,我是否需要或必须使用 certificatePinner
。换句话说,代码B是否比代码A更安全?
证书固定应该有助于某些 类 攻击
- 任何 受信任的证书颁发机构被黑客攻击并为您的域生成有效证书,例如 MITM 攻击被一个有侵略性的政府。
- 您的应用 运行 在具有额外可信证书的设备上运行,例如由提供 phone. 的公司安装
我认为一般来说,如果您从两个主要 CA 颁发证书,例如verisign,你会固定到他们的签名证书而不是你自己的。这是因为您可能会例行公事地为您的服务器生成新证书。