SSLを使用してHAProxyサーバーに接続すると、ランダムに表示される接続エラーが発生します。これらの障害はJDKバージョン1.7.0_21および1.7.0_25で発生しますが、1.7.0_04または1.6.0_38では発生しないことを確認しました。
例外は
_ Exception in thread "main" javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
at Sun.security.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.Java:397)
at SSLTest2.main(SSLTest2.Java:52)
at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at Sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:57)
at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:43)
at Java.lang.reflect.Method.invoke(Method.Java:601)
at com.intellij.rt.execution.application.AppMain.main(AppMain.Java:120)
_
これらの障害は、TLS SSLコンテキストを使用している場合にのみ発生し、デフォルトのコンテキストでは発生しません。次のコードはループ内で1000回実行され、ループが完了する前に障害が発生します(接続の約2%が失敗します)。
_SSLContext sslcontext = SSLContext.getInstance("TLS");
sslcontext.init(null, null, null);
SSLSocketFactory factory = sslcontext.getSocketFactory();
SSLSocket socket = (SSLSocket)factory.createSocket("myserver", 443);
//socket.startHandshake();
SSLSession session = socket.getSession();
session.getPeerCertificates();
socket.close();
_
ただし、この方法でSSLコンテキストを作成した場合、前述のJavaバージョンのいずれでも接続障害は発生しません:
_SSLSocketFactory factory = (SSLSocketFactory)SSLSocketFactory.getDefault();
_
最初の方法は_SSLContextImpl$TLS10Context
_を使用し、後者は_SSLContextImpl$DefaultSSLContext
_を使用します。コードを見ると、例外が発生する原因となる違いは見当たりません。
なぜ失敗するのでしょうか。また、getDefault()
呼び出しを使用することの長所/短所は何ですか?
注:例外は、Apache HttpClient(バージョン4)を使用して最初に確認されました。このコードは、HttpClientで見られる問題を再現する最小のサブセットです。
これが_-Djavax.net.debug=ssl
_:を追加するときに表示されるエラーです
_main, READ: TLSv1 Alert, length = 2
main, RECV TLSv1 ALERT: fatal, bad_record_mac
%% Invalidated: [Session-101, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA]
main, called closeSocket()
main, handling exception: javax.net.ssl.SSLException: Received fatal alert: bad_record_mac
main, IOException in getSession(): javax.net.ssl.SSLException: Received fatal alert: bad_record_mac
_
もう1つの情報は、プロキシサーバーでDiffie-Hellmanをオフにしても、エラーは発生しないということです。
症状から判断すると、私は推測これは TLS false start を使用しているブラウザに関連しています。これはGoogleが導入したクライアント側のトリックです- TLSの前後を減らす :
不正スタートは主にブラウザによって制御され、公式のSSL仕様に記載されているデータの2回のラウンドトリップパスを1回のラウンドトリップパスに減らすことで機能します。これは、Finishedメッセージと最初のApplicationDataメッセージを2つの別個のパッケージに入れてサーバーから確認を取得した後にのみ送信するのではなく、1回のディスパッチで送信するようにクライアントに指示することによって行われました。
Googleは、SSLを現在提供するには費用がかかりすぎると感じているウェブサイトにとってより口に合うようにするための公式標準としてFalseStartを提案しました。 False Startは、エンドユーザーとWebサイト間で受け渡されるデータを保護するために必要な暗号化キーやその他の変数をネゴシエートするハンドシェイクを短縮することで、プロトコルの使用によるパフォーマンスの低下を減らすことを目的としていました。
Mozilla Firefoxで発生した関連する問題 :(私の強調)から
これまでのところ、False Startとの現在または以前の互換性の問題があることがわかっている製品の不完全なリストには、(AFAICT)が含まれます:F5、A10、Microsoft TMG、Cisco ASA、ServerIron ADX、ESET、NetNanny、JavaのSSLサーバー実装のいくつかの構成。