如何提示用户接受或拒绝HTTPS证书?

时间:2014-09-30 23:46:49

标签: java android https

我的Android应用使用DefaultHttpClient API向外部HTTP服务器发送请求。我无法切换到HTTPS。

我的服务器使用的是自签名证书,默认情况下显然不受信任。

当应用程序连接到服务器时,我想向用户显示服务器证书的指纹,并让他接受或拒绝证书。

DefaultHttpClient可以实现吗?如果是,我是否可以看到代码片段,显示它是如何完成的。

我已经看到许多假设的解决方案和类似的问题,但没有一个对我有效。

2 个答案:

答案 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.