11

SSL ソケットから読み取っていますが、ホストが証明書と一致しません (例: host = "localhost")。例外が発生することが予想されますが、次のコードはリモート サーバーと問題なく通信します。

try (
    final Socket socket = SSLSocketFactory.getDefault().createSocket(host, port);
    final OutputStream os = socket.getOutputStream();
    final InputStream is = socket.getInputStream()) {

    os.write(("HEAD / HTTP/1.1\r\nHost: " + host + "\r\nConnection: close\r\n\r\n").getBytes());
    os.flush();

    final byte[] bytes = new byte[1024];
    int n;
    while ((n = is.read(bytes)) != -1) {
        System.out.print(new String(bytes, 0, n));
    }
    System.out.println();
} catch (final IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

したがって、私は別のアプローチを試しました:

try {
    final HttpURLConnection conn = (HttpURLConnection) new URL("https://" + host + ":" + port + "/").openConnection();

    try (InputStream is = conn.getInputStream()) {
        IOUtils.copy(is, System.out);
    } catch (final IOException e1) {
        try (InputStream es = conn.getErrorStream()) {
            if (es != null) {
                IOUtils.copy(es, System.out);
            }
        }
    }
} catch (final IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

残念ながら、まだ SSL 例外は発生せず、ログに警告が表示されるだけです。 2013-07-31 16:02:27,182 WARN nio - javax.net.ssl.SSLException: Received fatal alert: certificate_unknown

証明書が一致しない場合に SSL 例外を取得する方法は?

4

2 に答える 2

21

SSL/TLS プロトコル仕様はモジュール化されており、リモート ホストの認証に使用される仕様から切り離されています。これらの他の仕様は、証明書自体が信頼できることの検証 (RFC 3280/5280) と、証明書の ID の検証 (RFC 6125 または HTTPS の RFC 2818) の 2 つのカテゴリに分けられます。

JSSE は、SSL プロトコルと証明書の検証をSSLSocket(またはSSLEngine) API に統合しますが、識別子の検証は処理しません (これも同様に重要です)。

これは主に、SSLSocket/SSLEngineが任意のアプリケーション プロトコル (HTTP、IMAP、SMTP、LDAP など) に適用できるという事実によるものですが、識別子を検証するための規則は、RFC までは (わずかなバリエーションで) 異なる仕様でした。 6125 (これはまだかなり最近のものです)。

HttpsURLConnectionHostnameVerifierは、HTTPS 仕様 (RFC 2818、セクション 3.1) に準拠する も使用するため、両方を処理します。SSLSocketこれは/ SSLEngineAPIとは別に行われます。他のプロトコルについては、プロトコル仕様に記載されている内容を実装する必要がある場合があります。

SSLSocketそうは言っても、Java 7 以降、 / SSLEngineAPIの一部として証明書の ID を直接検証するメカニズムがあります。

SSLParameters sslParams = new SSLParameters();
sslParams.setEndpointIdentificationAlgorithm("HTTPS");
sslSocket.setSSLParameters(sslParams);

これを使用すると、ホスト名が一致しない場合に例外がスローされます。

HTTPS と RFC 6125 のより統一された仕様との間に大きな違いはありません (後者が IP アドレスを範囲外と見なすという事実を除けば)。HTTPS を使用していない場合でも、一般的に、その識別仕様を他のプロトコルに使用することは理にかなっています。(おそらく、"RFC 6125" エンドポイント識別アルゴリズムは、Java の新しいバージョンで提供される可能性があります。)

于 2013-07-31T20:09:11.957 に答える
3

ホスト名の照合は SSL の一部ではなく、HTTPS の一部です。たとえば、javax.net.ssl.HostnameVerifier を参照してください。

引用したログは、SSLExceptionHttpsURLConnection によってスローされたことを示しています。

于 2013-07-31T19:10:38.333 に答える