我的Android应用使用DefaultHttpClient API向外部HTTP服务器发送请求。我无法切换到HTTPS。
我的服务器使用的是自签名证书,默认情况下显然不受信任。
当应用程序连接到服务器时,我想向用户显示服务器证书的指纹,并让他接受或拒绝证书。
DefaultHttpClient可以实现吗?如果是,我是否可以看到代码片段,显示它是如何完成的。
我已经看到许多假设的解决方案和类似的问题,但没有一个对我有效。
答案 0 :(得分:1)
我终于找到了一个有效的解决方案。这是片段:
public class MySocketFactory implements SocketFactory, LayeredSocketFactory {
private SSLContext mSslContext = null;
{
try {
mSslContext = SSLContext.getInstance("TLS");
TrustManager trustManager = new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// NOTE : This is where we can calculate the certificate's fingerprint,
// show it to the user and throw an exception in case he doesn't like it
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
};
mSslContext.init(null, new TrustManager[]{ trustManager }, new SecureRandom());
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public Socket connectSocket(Socket socket, String host, int port,
InetAddress localAddress, int localPort, HttpParams params)
throws IOException, UnknownHostException, ConnectTimeoutException {
int connTimeout = HttpConnectionParams.getConnectionTimeout(params);
int soTimeout = HttpConnectionParams.getSoTimeout(params);
SocketAddress socketAddress = new InetSocketAddress(localAddress, localPort);
socket.bind(socketAddress);
socket.connect(new InetSocketAddress(host, port), connTimeout);
socket.setSoTimeout(soTimeout);
return socket;
}
@Override
public Socket createSocket() throws IOException {
return mSslContext.getSocketFactory().createSocket();
}
@Override
public boolean isSecure(Socket sock) throws IllegalArgumentException {
return true;
}
@Override
public Socket createSocket(Socket socket, String host, int port,
boolean autoClose) throws IOException, UnknownHostException {
return mSslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
}
}
然后你可以像这样实例化你的DefaultHttpClient:
HttpParams httpParameters = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParameters, 5000);
DefaultHttpClient result = new DefaultHttpClient(httpParameters);
MySocketFactory mySocketFactory = new MySocketFactory();
Scheme scheme = new Scheme("https", mySocketFactory, port);
result.getConnectionManager().getSchemeRegistry().register(scheme);
我尝试了它确实有效!
答案 1 :(得分:0)
DefaultHTTPClient,
是不可能的,因为信任匹配发生在较低级别,在SSL堆栈(JSSE或OpenSSL或Android使用的任何用途)中。
最简单,最便宜的解决方案是根本不使用自签名证书。使用CA签名的证书。你花费的费用已经超过了它的成本,你将花费更多的时间,它可能是值得的。付钱给CA.