【问题标题】:Android Java SSL Sockets - AllowAllHostNameVerifierAndroid Java SSL 套接字 - AllowAllHostNameVerifier
【发布时间】:2015-05-21 07:10:48
【问题描述】:

首先我想说的是,我正在探索 SSL 套接字的世界,网上没有那么多资料,我已经阅读了 StackOverflow 上的大部分主题,但我仍然对 TrustManager 的概念感到困惑,密钥库、主机名验证器... 所以我必须编写一个 Java 客户端(单向 SSL)来连接一些使用 SSL 的服务器。 我正在做三种行为,即 Android 的原生行为(我相信如果证书不受信任,它就不会处理握手)。 一个朴素的,带有一个自定义的 TrustManager 和空的 checkServerTrusted 函数。 现在我想使用 HostNameVerfier 来允许所有主机名。 但老实说,我有点迷路了,我已经搜索了好几天,互联网上没有关于 android ssl 的好材料。 到目前为止,这是我的代码:

Naive custom TrustManager (empty checkServerTrusted)

SSLContext sslContext = SSLContext.getInstance("SSL");
TrustManager trustManagerNaive =    new X509TrustManager(){
        @Override
        public void checkClientTrusted(
                X509Certificate[] chain,
                String authType)
                throws CertificateException {
            // TODO Auto-generated method stub
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public void checkServerTrusted(
                X509Certificate[] chain,
                String authType)
                throws CertificateException {
            // TODO Auto-generated method stub
        }
    };

sslContext.init(null, new TrustManager[]{trustManagerNaive}, null);

SSLSocketFactory socketFactory = (SSLSocketFactory)sslContext.getSocketFactory();
SSLSocket socket = (SSLSocket)socketFactory.createSocket(host, Integer.parseInt(port_number_et.getText().toString()));

//Native Android behavior (does not accept any untrusted certificate)
SSLSocketFactory socketFactory = (SSLSocketFactory)SSLSocketFactory.getDefault();
SSLSocket socket = (SSLSocket)socketFactory.createSocket(host, Integer.parseInt(port_number_et.getText().toString()));                      

【问题讨论】:

    标签: java android sockets ssl


    【解决方案1】:

    这是一个带有“不受信任”证书的运行示例:

    KeyStore keyStore = KeyStore.getInstance("BKS");
    InputStream in = getContext().getAssets().open(Constants.KEYSTORE_FILENAME);
    keyStore.load(in, Constants.KEYSTORE_PASSWORD);
    in.close();
    
    SSLSocketFactory socketFactory = new SSLSocketFactory(keyStore);
    socketFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    SchemeRegistry registry = new SchemeRegistry();
    registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
    registry.register(new Scheme("https", socketFactory, 443));
    BasicHttpParams basicHttpParams = new BasicHttpParams();
    HttpProtocolParams.setVersion(basicHttpParams, HttpVersion.HTTP_1_1);
    HttpProtocolParams.setContentCharset(basicHttpParams, HTTP.UTF_8);
    ThreadSafeClientConnManager ccm = new ThreadSafeClientConnManager(basicHttpParams, registry);
    
    httpClient = new DefaultHttpClient(ccm, basicHttpParams);
    

    一些解释:

    • 使用不受信任的证书创建密钥库
    • 加载密钥库并在 SSLSocketFactory 中设置
    • 将 hostnameVerifier 设置为 ALLOW_ALL_HOSTNAME_VERIFIER(因为证书不受信任)

    那么你可以使用这个 httpClient 来进行 http 或 https 请求,如下所示:

    httpClient.execute(httpGet, new BasicHttpContext());
    

    【讨论】:

    • 感谢您的回答,但我认为在我的情况下,我不需要密钥库,因为我的客户不需要经过身份验证。此外,我没有使用 Http,而只是使用普通套接字。另外,正如我在帖子中所说,方法 setHostnameVerifier 在我的 socketfactory 对象上不可用。
    • 如果要创建 ssl 连接,则需要证书来加密数据。如果你在服务器端有一个未经验证的证书,你需要下载这个证书并将它放在 SSLSocketFactory 的 keyStore 中。否则使用 ssl 连接毫无意义。但如果你想这样做,这里有一个允许一切的解决方案:stackoverflow.com/questions/2642777/…
    • 实际上我希望它不起作用,我希望它允许我在一个主题上工作的所有内容显示 android ssl 连接上的流程,并且我想创建一个客户端(它不无论证书的有效性如何,都必须验证自己)连接到服务器。它应该接受所有人的一切。
    • 所以你可以使用我在上一条评论中发布的链接的解决方案。这将起作用,但会使 ssl 的全部目的无效
    • 是的,我想使用它,但正如我告诉你的,我认为 setHostnameVerifier 是一种旧方法,因为它不再可用,因为 SSLSocketFactory 的构造函数它不应该接受任何参数。我的 IDE(eclipse)至少是这么说的。
    猜你喜欢
    • 2014-08-17
    • 1970-01-01
    • 2011-11-28
    • 2017-06-18
    • 1970-01-01
    • 2015-11-12
    • 2015-11-29
    • 1970-01-01
    • 2014-01-26
    相关资源
    最近更新 更多