【发布时间】:2014-06-25 17:55:52
【问题描述】:
我尝试了几天来了解如何从服务器获取证书,我们正在处理 SSL 通信,为了识别服务器,我需要检查其认证。
关于代码的几件事,我正在使用 HttpClient 并且 - 我不想从认证中创建一个密钥存储并将其添加到“信任存储”作为 this 链接和许多其他建议。
所以,我为了获得认证所做的就是实现X509HostnameVerifier,并在其verify()方法中做:
session.getPeerCertificates();
但该功能通过异常:
An exception occurred: javax.net.ssl.SSLPeerUnverifiedException
代码如下:
import java.io.IOException;
import java.security.cert.Certificate;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
public class MyHostnameVerifier implements ch.boye.httpclientandroidlib.conn.ssl.X509HostnameVerifier {
@Override
public boolean verify(String hostname, SSLSession session) {
Certificate[] certificates;
try {
certificates = session.getPeerCertificates();
// if connection doesn't contain any certificate - drop it, it might be an hacker.
if (certificates == null || certificates.length == 1)
return true;
} catch (SSLPeerUnverifiedException e) {
}
return true;
}
@Override
public void verify(String hostname, SSLSocket socket) throws IOException {
socket.getSession().getPeerCertificates(); // exception
}
@Override
public void verify(String hostname, String[] arg1, String[] arg2) throws SSLException {
}
@Override
public void verify(String arg0, java.security.cert.X509Certificate arg1) throws SSLException {
}
}
及用法示例:
PoolingClientConnectionManager cm = new PoolingClientConnectionManager();
// Increase max total connection to 10
cm.setMaxTotal(GlobalConstants.HTTP_CLIENT_MAX_TOTAL_CONNECTIONS);
HttpParams httpParameters = new BasicHttpParams();
int timeoutConnection = CONNECTION_TIMEOUT_MS_DEFAULT;
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
HostnameVerifier hostnameVerifier = new MyHostnameVerifier();
SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();
socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
cm.getSchemeRegistry().register(new ch.boye.httpclientandroidlib.conn.scheme.Scheme("https", 443, socketFactory));
DefaultHttpClient httpClient = new DefaultHttpClient(cm, httpParameters);
【问题讨论】:
-
我认为您通常在 Java 中使用自定义
TrustManager。调用TrustManager方法时会提供服务器的证书。 -
@jww 你说得对,我设法解决了这个问题,并会在接下来的几天内发布解决方案。
-
你介意在这里分享解决方案吗?
-
@RSC 我发布了我的解决方案。我希望它会很清楚,如果你觉得它有用 - 请评价它:)
-
谢谢达尔维克。因此,您的解决方案通过 Socket 连接。我也使用套接字做了类似的事情,并且正在测试我对 Main in the Middle 攻击的连接,我注意到如果攻击者使用 HTTP 代理(如 Fiddler),套接字连接将直接连接到服务器(然后验证 SSL 证书) 虽然所有的 http 通信仍然会被攻击者捕获(假设他能够在用户设备上安装他的自定义证书)。你遇到过这样的事情吗?
标签: android ssl httpclient