2
我剛剛實施證書鎖定下面的教程,我發現。但是現在我注意到它忽略了主機名驗證,上帝知道它忽略了什麼。證書鎖定忽略主機名驗證
這裏是我有:
的SSLSocketFactory:
public class PinningSSLSocketFactory extends SSLSocketFactory {
SSLContext sslContext = SSLContext.getInstance("TLS");
PubKeyManager pkm;
public PinningSSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException,
KeyStoreException, UnrecoverableKeyException {
super(truststore);
pkm = new PubKeyManager();
TrustManager tm[] = { pkm };
sslContext.init(null, tm, null);
}
@Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException,
UnknownHostException {
return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
}
@Override
public Socket createSocket() throws IOException {
return sslContext.getSocketFactory().createSocket();
}
public void setContext(Context context) {
pkm.setContext(context);
}
}
X509TrustManager:
public class PubKeyManager implements X509TrustManager {
public Context mContext;
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
if (chain == null) {
throw new IllegalArgumentException("checkServerTrusted: X509Certificate array is null");
}
if (!(chain.length > 0)) {
throw new IllegalArgumentException("checkServerTrusted: X509Certificate is empty");
}
if (!(null != authType && authType.equalsIgnoreCase("RSA"))) {
throw new CertificateException("checkServerTrusted: AuthType is not RSA");
}
// Perform customary SSL/TLS checks
// get request cert
try {
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
tmf.init((KeyStore) null);
for (TrustManager trustManager : tmf.getTrustManagers()) {
((X509TrustManager) trustManager).checkServerTrusted(chain, authType);
}
} catch (Exception e) {
throw new CertificateException(e);
}
//get stored certificate
expected = //compare both certs
if (!expected) {
throw new CertificateException("checkServerTrusted");
}
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
public void setContext(Context context) {
mContext = context;
}
}
獲得的HttpClient:
public DefaultHttpClient getPinningHttpClient(){
try {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
PinningSSLSocketFactory sf = new PinningSSLSocketFactory(trustStore);
sf.setContext(context);
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", sf, 443));
ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
return new DefaultHttpClient(ccm, params);
} catch (Exception e) {
e.printStackTrace();
}
return new DefaultHttpClient();
}
我的問題是如何解決日缺少主機名驗證以及其他缺失的驗證,這些驗證可能會以這種方式破壞業務。
感謝您給予的任何幫助。
我已經基本上遵循該頁面上的示例項目來做我現在擁有的東西。問題在於我們將質量證書放在質量服務器上,即使URL與證書上的URL不匹配,它也會接受請求。 Só我假設使用我的'PinningSSLSocketFactory'已經以某種方式忽略了主機名驗證。如果我使用默認的'SSLSocketFactory'由於主機名驗證,它不允許連接。 –
@HugoAlves:再次 - 釘住是更有力的驗證方法,因爲您知道證書或公鑰。只有在您需要檢查您以前未知的證書是否可信時,才需要驗證鏈和主機名。這意味着可以省略主機名檢查。 –
好的,謝謝你的幫助。感覺這是一個我沒什麼專業知識的領域,我擔心通過將用戶的請求重定向到攻擊者的機器並竊取他們的信息,或者我已經打開了其他攻擊方式,這是一種可能的攻擊方式。我認爲主機名驗證會保護這一點。 –