43

Andoridバージョン4.1.1でAndroidアプリからURLに接続しようとすると、質問のタイトルにエラーが表示されますが、Andoridバージョン4.0.4または3.1から同じURLに接続しようとすると、すべて正常に動作します。

コードフラグメント:

    try {
        .
        .
        .
        URL url = new URL(urlStr);
        Log.i(TAG,"[ URL ] " + urlStr);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        int size = conn.getContentLength();
        int responsecode = conn.getResponseCode();
        Log.d(TAG, "Responsecode: " + responsecode);
        .
        .
        .
        } catch (Exception e) {
        e.printStackTrace();
        }


private static void trustAllHosts() {

        TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return new java.security.cert.X509Certificate[] {};
            }

            public void checkClientTrusted(X509Certificate[] chain,
                            String authType) throws CertificateException {
            }

            public void checkServerTrusted(X509Certificate[] chain,
                            String authType) throws CertificateException {
            }
        } };

        try {
                SSLContext sc = SSLContext.getInstance("TLS");
                sc.init(null, trustAllCerts, new java.security.SecureRandom());
                HttpsURLConnection
                                .setDefaultSSLSocketFactory(sc.getSocketFactory());
        } catch (Exception e) {
                System.out.println("IOException : HTTPSRequest::trustAllHosts");
                e.printStackTrace();
        }
    }

しかし、ここで私が明確にしていることの1つは、「証明書は自己署名証明書であり、KeyStoreに含まれていない可能性があります。

この例外がAndroidVerison4.1.1OSのおかげでのみ発生する理由がわかりません。

フルスタックトレース

01-31 10:26:08.348: W/System.err(3158): java.io.IOException: Hostname <URL> was not verified
01-31 10:26:08.348: W/System.err(3158):     at libcore.net.http.HttpConnection.verifySecureSocketHostname(HttpConnection.java:223)
01-31 10:26:08.348: W/System.err(3158):     at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:446)
01-31 10:26:08.348: W/System.err(3158):     at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:289)
01-31 10:26:08.348: W/System.err(3158):     at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:239)
01-31 10:26:08.348: W/System.err(3158):     at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:273)
01-31 10:26:08.348: W/System.err(3158):     at libcore.net.http.HttpURLConnectionImpl.getHeaderField(HttpURLConnectionImpl.java:130)
01-31 10:26:08.348: W/System.err(3158):     at java.net.URLConnection.getHeaderFieldInt(URLConnection.java:544)
01-31 10:26:08.348: W/System.err(3158):     at java.net.URLConnection.getContentLength(URLConnection.java:316)
01-31 10:26:08.348: W/System.err(3158):     at libcore.net.http.HttpsURLConnectionImpl.getContentLength(HttpsURLConnectionImpl.java:191)
01-31 10:26:08.348: W/System.err(3158):     at com.ih.util.HelpVideoServices$downloadTask.run(HelpVideoServices.java:172)                                
4

10 に答える 10

62

何の意味もない証明書を使用して実行していて、それらをバイパスしたい場合は、このコードを機能させるためにnullホスト名ベリファイアも追加する必要があります

HttpsURLConnection.setDefaultHostnameVerifier(new NullHostNameVerifier());
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, new X509TrustManager[]{new NullX509TrustManager()}, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());

そして、ホストのコード:

import javax.net.ssl.HostnameVerifier ;
import javax.net.ssl.SSLSession;

public class NullHostNameVerifier implements HostnameVerifier {

    @Override   
    public boolean verify(String hostname, SSLSession session) {
        Log.i("RestUtilImpl", "Approving certificate for " + hostname);
        return true;
    }

}

これは1回実行する必要がありますが、接続オブジェクトに変更を加える場合は、再度実行する必要がある場合があります。

于 2013-03-06T16:02:16.260 に答える
19

@Noamの答えに加えて、これは完全な例です。

/**
 * Disables the SSL certificate checking for new instances of {@link HttpsURLConnection} This has been created to
 * aid testing on a local box, not for use on production.
 */
private static void disableSSLCertificateChecking() {
    TrustManager[] trustAllCerts = new TrustManager[] {
        new X509TrustManager() {

            @Override
            public void checkClientTrusted(java.security.cert.X509Certificate[] x509Certificates, String s) throws java.security.cert.CertificateException {
                // not implemented
            }

            @Override
            public void checkServerTrusted(java.security.cert.X509Certificate[] x509Certificates, String s) throws java.security.cert.CertificateException {
                // not implemented
            }

            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }

        }
    };

    try {

        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {

            @Override
            public boolean verify(String s, SSLSession sslSession) {
                return true;
            }

        });
        SSLContext sc = SSLContext.getInstance("TLS");
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

    } catch (KeyManagementException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
}

それが役に立てば幸い

于 2014-10-19T22:29:45.413 に答える
11

これは、SSLで宣言したCN(共通名)が、HTTPリクエストを送信している実際のURLにも一致しないために発生する可能性があります。

その場合は、新しいSSLを作成し、現在のCNを入力します。これで問題は解決するはずです。

于 2014-11-04T15:21:37.630 に答える
7

HTTPSUrlConnectionを使用して、4.1.1および4.1.2でこの問題が発生しました。

少し調べてみると、私が扱っているApacheサーバーにhttpsトラフィックを提供する複数の仮想ホストがあり、少なくともJellyBeanの前にAndroidでSNIの問題が発生したことがわかりました(JBで機能していたという未確認の報告があります)。

私の場合、httpsトラフィックを提供する3つの仮想ホストがありました。

  • mydomain.com
  • api.mydomain.com(私が対処しようとしていたもの)
  • admin.mydomain.com

次のようにopenssl_clientを使用してapi。*をプローブします。

openssl s_client -debug -connect api.mydomain.com:443

...常にルートドメインの証明書を返しました-出力に埋め込まれているのは次のようなものでした:

Certificate chain
 0 s:/OU=Domain Control Validated/CN=mydomain.com
 ...

...openssl_clientコマンドラインでサーバー名を指定します。

openssl s_client -debug -servername api.mydomain.com -connect api.mydomain.com:443

...私が期待していた証明書を返しました:

Certificate chain
 0 s:/OU=Domain Control Validated/CN=api.mydomain.com

ルートドメインの仮想ホストを別の物理ホストに移動することで、問題を解決することができました。

Android HostnameVerifierは、複数のサブドメインを仮想ホストとして並べて使用できるようですが、ルートドメインを同じapache内の仮想ホストとして使用すると問題が発生します。

私はsys-admin/dev-opsではないので、私が気付いていない問題を解決できた可能性のあるApache構成オプションがある可能性があります。

于 2013-07-08T17:13:55.267 に答える
6

SSL証明書はドメインでのみ機能し、IPアドレスでは機能しないことに注意してください。

IPを使用する場合は、以下のコードを挿入してください

HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier()
        {
            @Override
            public boolean verify(String hostname, SSLSession session)
            {
                if(hostname.equals("127.0.0.1"))
                     return true;
            }
        });
于 2018-05-15T13:52:22.183 に答える
2

AndroidはSSL接続を設定できないと思います。接続を確立するホスト名ではなく、他のホスト名の証明書である可能性があります。ここここでドキュメントを読んでください。

于 2013-01-31T06:44:15.067 に答える
1

あなたの問題はあなたのURLが「https」を介して解決されたものである可能性があります。すべての文字列URLを「http」に変換する必要があります。そうすれば機能します。

編集:

SchemeRegistry schemeRegistry = new SchemeRegistry ();

schemeRegistry.register (new Scheme ("http",
    PlainSocketFactory.getSocketFactory (), 80));
schemeRegistry.register (new Scheme ("https",
    new CustomSSLSocketFactory (), 443));

ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager (
    params, schemeRegistry);

return new DefaultHttpClient (cm, params);

CustomSSLSocketFactory:

public class CustomSSLSocketFactory extends org.apache.http.conn.ssl.SSLSocketFactory
{
    private SSLSocketFactory FACTORY = HttpsURLConnection.getDefaultSSLSocketFactory ();

    public CustomSSLSocketFactory ()
    {
        super(null);
        try
        {
            SSLContext context = SSLContext.getInstance ("TLS");
            TrustManager[] tm = new TrustManager[] { new FullX509TrustManager () };
            context.init (null, tm, new SecureRandom ());

            FACTORY = context.getSocketFactory ();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    public Socket createSocket() throws IOException
    {
        return FACTORY.createSocket();
    }

    // TODO: add other methods like createSocket() and getDefaultCipherSuites().
    // Hint: they all just make a call to member FACTORY 
}

FullX509TrustManagerは、javax.net.ssl.X509TrustManagerを実装するクラスですが、実際に作業を実行するメソッドはありません。サンプルを入手してください[ここ][1]。

幸運を!

于 2013-01-31T07:44:16.283 に答える
1

これは私にとってよりうまく機能します->CHANGINGStrictHostnameVerifier()

https://developer.android.com/reference/org/apache/http/conn/ssl/StrictHostnameVerifier

    HostnameVerifier hostnameVerifier = new HostnameVerifier() {
    @Override
    public boolean verify(String hostname, SSLSession session) {
        HostnameVerifier hv = new StrictHostnameVerifier();

        return hv.verify("example.com", session);
       }
    };

https://developer.android.com/training/articles/security-ssl#javaを使用してください

    // Tell the URLConnection to use our HostnameVerifier
    URL url = new URL("https://example.org/");
    HttpsURLConnection urlConnection = 
   (HttpsURLConnection)url.openConnection();
   urlConnection.setHostnameVerifier(hostnameVerifier);
于 2018-09-19T17:01:39.847 に答える
0

Amazonのドキュメントから: バケットの制限

「SSLで仮想ホストスタイルのバケットを使用する場合、SSLワイルドカード証明書はピリオドを含まないバケットにのみ一致します。これを回避するには、HTTPを使用するか、独自の証明書検証ロジックを記述します。」

最も簡単な方法は、ピリオドなしで一意のバケット名を作成するようです。

「bucketname.mycompany.com」の代わりに、「bucketnamemycompany」やその他のDNS準拠のバケット名など。

于 2015-10-08T21:36:30.083 に答える
0

Kotlinの場合:

fun HttpsURLConnection.trustCert() {
            try {
                //Accepts every hostname
                this.hostnameVerifier = HostnameVerifier { hostname, _ ->
                    println(hostname) //To be hardcoded/as needed
                    true
                }
                val trustMgr:Array<TrustManager> = arrayOf(object : X509TrustManager {
                    override fun checkClientTrusted(certs: Array<out X509Certificate>?, authType: String?) {}
                    override fun checkServerTrusted(certs: Array<out X509Certificate>?, authType: String?) {}
                    override fun getAcceptedIssuers(): Array<X509Certificate>? = null
                })
                this.sslSocketFactory = SSLContext.getInstance("TLS").also {
                    it.init(null, trustMgr, SecureRandom())
                }.socketFactory
            } catch (e: Exception) {
                prinntln("SSL self-signed certificate processing error due to ${e.message}")
            }
        }

使用法:

val conn = URL(Uri.Builder().also { 
    it.scheme("https")
    it.encodedAuthority("$serverIp:$serverPort")
}.build().toString()).openConnection() as HttpsURLConnection
conn.trustCert()
val respCode = conn.responseCode
if(respCode == 200) {
    //do something (eg: read inputStream)
}
于 2020-11-17T11:00:26.267 に答える