Java 如何提示用户接受或拒绝HTTPS证书?
我的Android应用程序使用DefaultHttpClient API向外部HTTP服务器发送请求。我无法切换到HTTPS 我的服务器使用自签名证书,默认情况下该证书显然不受信任 当应用程序连接到服务器时,我想向用户显示服务器证书的指纹,并让用户接受或拒绝证书 对于DefaultHttpClient,这可能吗?如果是的话,我可以看一段代码片段来说明它是如何完成的吗Java 如何提示用户接受或拒绝HTTPS证书?,java,android,https,Java,Android,Https,我的Android应用程序使用DefaultHttpClient API向外部HTTP服务器发送请求。我无法切换到HTTPS 我的服务器使用自签名证书,默认情况下该证书显然不受信任 当应用程序连接到服务器时,我想向用户显示服务器证书的指纹,并让用户接受或拒绝证书 对于DefaultHttpClient,这可能吗?如果是的话,我可以看一段代码片段来说明它是如何完成的吗 我已经看到了许多解决这个问题和类似问题的假定解决方案,但没有一个对我有效。使用DefaultHTTPClient是不可能的,因为信
我已经看到了许多解决这个问题和类似问题的假定解决方案,但没有一个对我有效。使用
DefaultHTTPClient是不可能的,
因为信任匹配发生在较低的级别,在SSL堆栈中(JSSE或OpenSSL或Android使用的任何东西)
最简单、最便宜的解决方案是根本不使用自签名证书。使用CA签名的证书。你已经花了超过它的成本,你将花更多的时间,它可能是值得的。把钱付给CA。我终于找到了一个可行的解决方案。以下是片段:
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);
我试过了,它确实有效 “我见过很多解决这个问题和类似问题的方法,但没有一种对我有效”——列出它们并解释你遇到的具体问题。下次我尝试失败时,我会在这里发布具体的问题。问题是昨晚我尝试了几种不同的方法,但没有一种对我有效,在我厌倦了之后,我就懒得记下每种假设的解决方案。你说“这不可能”是因为你知道这是事实还是仅仅因为你不知道答案?我这样问是因为我已经知道如何让DefaultHttpClient使用应用程序的自定义密钥库,其中信任匹配也发生在较低的级别,所以您提供的原因并不能完全说服我。此外,我的应用程序将与用户的个人、支持DynDNS的Raspberry Pi服务器一起使用,因此不可能提前知道使用了哪个证书。这就是为什么我希望用户能够通过指纹接受或拒绝。