【问题标题】:How to make below HTTPs connection over Android secure如何通过 Android 安全地进行以下 HTTPs 连接
【发布时间】:2026-01-07 18:20:07
【问题描述】:

我在安全套接字层上有下面的东西,它使用信任管理器创建了一个隧道,但我不明白 ALLOW ALL HOST NAME 的影响是什么。有人可以解释吗?

有人可以建议我需要对代码进行哪些更改吗?

        public class EasySSLSocketFactory implements SocketFactory, LayeredSocketFactory {

            private SSLContext sslcontext = null;

            private SSLContext createEasySSLContext() throws IOException {
                try {
                    SSLContext context = SSLContext.getInstance("TLS");
                    context.init(null, new TrustManager[] { new EasyX509TrustManager(null) }, null);
                    return context;
                } catch (Exception e) {
                    throw new IOException(e.getMessage());
                }
            }

            private SSLContext getSSLContext() throws IOException {
                if (this.sslcontext == null) {
                    this.sslcontext = createEasySSLContext();
                }
                return this.sslcontext;
            }

            /**
             * @see org.apache.http.conn.scheme.SocketFactory#connectSocket(java.net.Socket, java.lang.String, int,
             *      java.net.InetAddress, int, org.apache.http.params.HttpParams)
             */
            public Socket connectSocket(Socket sock, String host, int port, InetAddress localAddress, int localPort,
                    HttpParams params) throws IOException, UnknownHostException, ConnectTimeoutException {
                int connTimeout = HttpConnectionParams.getConnectionTimeout(params);
                int soTimeout = HttpConnectionParams.getSoTimeout(params);
                InetSocketAddress remoteAddress = new InetSocketAddress(host, port);
                SSLSocket sslsock = (SSLSocket) ((sock != null) ? sock : createSocket());

                if ((localAddress != null) || (localPort > 0)) {
                    // we need to bind explicitly
                    if (localPort < 0) {
                        localPort = 0; // indicates "any"
                    }
                    InetSocketAddress isa = new InetSocketAddress(localAddress, localPort);
                    sslsock.bind(isa);
                }

                sslsock.connect(remoteAddress, connTimeout);
                sslsock.setSoTimeout(soTimeout);
                return sslsock;

            }

            /**
             * @see org.apache.http.conn.scheme.SocketFactory#createSocket()
             */
            public Socket createSocket() throws IOException {
                return getSSLContext().getSocketFactory().createSocket();
            }

            /**
             * @see org.apache.http.conn.scheme.SocketFactory#isSecure(java.net.Socket)
             */
            public boolean isSecure(Socket socket) throws IllegalArgumentException {
                return true;
            }

            /**
             * @see org.apache.http.conn.scheme.LayeredSocketFactory#createSocket(java.net.Socket, java.lang.String, int,
             *      boolean)
             */
            public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException,
                    UnknownHostException {
                return getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose);
            }

            // -------------------------------------------------------------------
            // javadoc in org.apache.http.conn.scheme.SocketFactory says :
            // Both Object.equals() and Object.hashCode() must be overridden
            // for the correct operation of some connection managers
            // -------------------------------------------------------------------

            public boolean equals(Object obj) {
                return ((obj != null) && obj.getClass().equals(EasySSLSocketFactory.class));
            }

            public int hashCode() {
                return EasySSLSocketFactory.class.hashCode();
            }
            }


        public class EasyX509TrustManager implements X509TrustManager {

            private X509TrustManager standardTrustManager = null;

            /**
             * Constructor for EasyX509TrustManager.
             */
            public EasyX509TrustManager(KeyStore keystore) throws NoSuchAlgorithmException, KeyStoreException {
                super();
                TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                factory.init(keystore);
                TrustManager[] trustmanagers = factory.getTrustManagers();
                if (trustmanagers.length == 0) {
                    throw new NoSuchAlgorithmException("no trust manager found");
                }
                this.standardTrustManager = (X509TrustManager) trustmanagers[0];
            }

            /**
             * @see javax.net.ssl.X509TrustManager#checkClientTrusted(X509Certificate[],String authType)
             */
            public void checkClientTrusted(X509Certificate[] certificates, String authType) throws CertificateException {
                standardTrustManager.checkClientTrusted(certificates, authType);
            }

            /**
             * @see javax.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate[],String authType)
             */
            public void checkServerTrusted(X509Certificate[] certificates, String authType) throws CertificateException {
                if ((certificates != null) && (certificates.length == 1)) {
                    certificates[0].checkValidity();
                } else {
                    standardTrustManager.checkServerTrusted(certificates, authType);
                }
            }

            /**
             * @see javax.net.ssl.X509TrustManager#getAcceptedIssuers()
             */
            public X509Certificate[] getAcceptedIssuers() {
                return this.standardTrustManager.getAcceptedIssuers();
            }
            }


        public static HttpClient getNewHttpClient() {
            try {
                KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
                trustStore.load(null, null);

                SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
                sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

                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) {
                return new DefaultHttpClient();
            }
        }

【问题讨论】:

  • 你的问题是SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER,你应该把它改成更合适的。
  • 知道我还能用什么吗?

标签: android http ssl https connection


【解决方案1】:

使用 AllowAllHostnameVerifier() 或 SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER 本质上关闭 使用 SSL 连接时的主机名验证。这是等价的 信任所有证书。

所以你需要更改你的主机名验证器:

选项是:

  1. BrowserCompatHostnameVerifier

    主机名必须与第一个 CN 或任何 主题替代。通配符可以出现在 CN 中,也可以出现在任何 主题替代。

    BROWSER_COMPATIBLE 和 STRICT 之间的唯一区别是 带有 BROWSER_COMPATIBLE 的通配符(例如 *.foo.com")匹配所有 子域,包括“a.b.foo.com.

  2. StrictHostnameVerifier

    主机名必须与第一个匹配 CN,或任何主题替代品。通配符可以出现在 CN 中,并且 在任何主题替代中。与 IE6 的一个不同之处在于我们如何 只检查第一个 CN。 IE6 允许匹配任何 CN 当下。我们决定追随 Sun Java 1.4 的脚步,并且只 检查第一个 CN。 (如果您需要检查所有 CN,请随时 编写你自己的实现!)。

    诸如“*.foo.com”之类的通配符只匹配相同的子域 级别,例如“a.foo.com”。它不匹配更深的子域 比如“a.b.foo.com”。

  3. 如果您想实现其中之一不存在的验证,您需要创建自己的主机名验证器。

Some basic information about Hostname Verification

【讨论】:

  • 谢谢@Than,这是非常简短且非常有用的解释。我将进行以下更改...再次非常感谢:)