GlassFish 5.1.0のSSL問題を対策する

この記事は、オープンソフトウェアとして広く利用されているアプリケーションサーバのGlassFish 5.1.0を構築した際に遭遇したSSLハンドシェイクに関するエラーの対策方法について紹介しています。

RHEL 8.5にGlassFish 5.1.0をインストールする手順については、以下の記事で紹介しています。

GlassFish 5.1.0のSSL問題を対策する

Eclipse FoundationからダウンロードしたGlassFish 5.1.0をRHEL 8.5の上で起動させると、以下のようなエラーがサーバログに記録されていました。

$ vi /opt/glassfish5/glassfish/domains/domain1/logs/server.log

・・・<途中省略>・・・ 

Caused by: javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
        at sun.security.ssl.Handshaker.activate(Handshaker.java:509)
        at sun.security.ssl.SSLSocketImpl.kickstartHandshake(SSLSocketImpl.java:1474)
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1346)
        at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:750)
        at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:123)
        at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
        at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
        at java.io.DataOutputStream.flush(DataOutputStream.java:123)
        at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:229)
        ... 12 more

この事象が発生した環境の詳細については、以下の通りです。

$ cat /etc/redhat-release
Red Hat Enterprise Linux release 8.5 (Ootpa)

$ java -version
openjdk version "1.8.0_242"
OpenJDK Runtime Environment (build 1.8.0_242-b08)
OpenJDK 64-Bit Server VM (build 25.242-b08, mixed mode)

$ /opt/glassfish5/bin/asadmin version
Version string could not be obtained from Server [localhost:4848].
(Turn debugging on e.g. by setting AS_DEBUG=true in your environment, to see the details.)
Using locally retrieved version string from version class.
Version = GlassFish Server Open Source Edition  5.1.0  (build default-private)
Command version executed successfully.

何が起こっているのか

「javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)」のエラーは、SSLハンドシェイク時に利用しようとしているプロトコルが無効化されているか又は暗号スイートが適切でない場合に発生するJavaのエラーです。

SSLハンドシェイクとは、クライアントとサーバー間で暗号化通信を確立するための手順です。このエラーメッセージが出力されている場合は、SSLサーバソケットの確立に失敗しているため、クライアントとサーバー間における暗号化通信ができません。

このエラーが発生する主な原因は、Javaランタイム環境(JRE)のバージョンが古いか又はサポートされていないプロトコルや暗号スイートを使用している場合です。古いバージョンのJREではサポートされないプロトコルやスイートが無効化されている場合があります。

Eclipse GlassFish Server Security Guideによると、GlassFish 5.1.0はSSL 3.0とTLS 1.0をサポートしているようです。

The newest version of the SSL standard is called Transport Layer Security (TLS). The GlassFish Server
supports the SSL 3.0 and the TLS 1.0 encryption protocols.

Eclipse GlassFish Server Security Guide, Release 5.1

Javaランタイム環境(JRE)を確認する

今回のGlassFish 5.1.0の構築には、java-1.8.0-openjdk(8u242)を利用しています。以下のJavaコンフィグの「jdk.tls.disabledAlgorithms」パラメータを確認してみます。

$ vi /lib/jvm/jre-1.8.0-openjdk/lib/security/java.security

・・・<途中省略>・・・

jdk.tls.disabledAlgorithms=SSLv3, RC4, DES, MD5withRSA, DH keySize < 1024, \
    EC keySize < 224, 3DES_EDE_CBC, anon, NULL

・・・<途中省略>・・・

「jdk.tls.disabledAlgorithms」パラメータは、引数に記述された暗号化アルゴリズムを利用できないように制御します。上記の設定では、SSL 3.0(SSLv3)は利用できませんが、TLS 1.0は利用できるようになっています。

ここで疑問は、GlassFish 5.1.0は現時点においてTLS 1.0を利用できるはずなのに、なぜかSSLハンドシェイクのエラーが発生しているという点です。

他に暗号化アルゴリズムを制御するJavaコンフィグが存在するのでしょうか?

調べていくとRHEL 8は、以下のJavaコンフィグの「jdk.tls.disabledAlgorithms」パラメータで暗号化アルゴリズムが制御されているようでした。

$ vi /etc/crypto-policies/back-ends/java.config

・・・<途中省略>・・・

jdk.tls.disabledAlgorithms=DH keySize < 2048, TLSv1, TLSv1.1, SSLv3, SSLv2, DHE_DSS, RSA_EXPORT, DHE_DSS_EXPORT, DHE_RSA_EXPORT, DH_DSS_EXPORT, DH_RSA_EXPORT, DH_anon, ECDH_anon, DH_RSA, DH_DSS, ECDH, 3DES_EDE_CBC, DES_CBC, RC4_40, RC4_128, DES40_CBC, RC2, HmacMD5

・・・<途中省略>・・・

RHEL 8では、デフォルトでTLS 1.0(TLSv1)、TLS 1.1(TLSv1.1)、SSL 2.0(SSLv2)及びSSL 3.0(SSLv3)の暗号化アルゴリズムが利用できないように設定されています。

2023年6月時点では、基本的にTLS 1.2以上を利用することが推奨されており、RHEL 8はデフォルトで上記のように設定されています。

対策方法について

GlassFish 5.1.0のアプリケーションがSSLハンドシェイクで利用するの暗号化プロトコルをTLS 1.2以上に変更することができれば問題は解決できるはずですが、自力でのプログラム修正は困難であるため、TLS 1.0を利用できるように設定変更していきます。

RHEL 8のJavaコンフィグを開き、「jdk.tls.disabledAlgorithms」パラメータの引数から「TLSv1」の記述を削除したのち保存します。

$ vi /etc/crypto-policies/back-ends/java.config

・・・<途中省略>・・・

jdk.tls.disabledAlgorithms=DH keySize < 2048, TLSv1.1, SSLv3, SSLv2, DHE_DSS, RSA_EXPORT, DHE_DSS_EXPORT, DHE_RSA_EXPORT, DH_DSS_EXPORT, DH_RSA_EXPORT, DH_anon, ECDH_anon, DH_RSA, DH_DSS, ECDH, 3DES_EDE_CBC, DES_CBC, RC4_40, RC4_128, DES40_CBC, RC2, HmacMD5

・・・<途中省略>・・・

GlassFish 5.1.0を再起動して、サーバログを確認します。

$ systemctl restart glassfish

$ systemctl status glassfish
● glassfish.service - GlassFish Server v5.1.0
   Loaded: loaded (/usr/lib/systemd/system/glassfish.service; enabled; vendor preset: disabled)
   Active: active (running) since Sun 2023-06-25 06:12:57 UTC; 10s ago
  Process: 8997 ExecStart=/opt/glassfish5/bin/asadmin start-domain (code=exited, status=0/SUCCESS)
 Main PID: 9016 (java)
    Tasks: 87 (limit: 24301)
   Memory: 420.9M
   CGroup: /system.slice/glassfish.service
           mq9016 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.242.b08-4.el8.x86_64/bin/java -cp /opt/glassfish5/glas>

 6月 25 06:12:34 rhel8.reafnex.net systemd[1]: Starting GlassFish Server v5.1.0...
 6月 25 06:12:57 rhel8.reafnex.net asadmin[8997]: Waiting for domain1 to start ...................
 6月 25 06:12:57 rhel8.reafnex.net asadmin[8997]: Successfully started the domain : domain1
 6月 25 06:12:57 rhel8.reafnex.net asadmin[8997]: domain  Location: /opt/glassfish5/glassfish/domains/domain1
 6月 25 06:12:57 rhel8.reafnex.net asadmin[8997]: Log File: /opt/glassfish5/glassfish/domains/domain1/logs/ser>
 6月 25 06:12:57 rhel8.reafnex.net asadmin[8997]: Admin Port: 4848
 6月 25 06:12:57 rhel8.reafnex.net asadmin[8997]: Command start-domain executed successfully.
 6月 25 06:12:57 rhel8.reafnex.net systemd[1]: Started GlassFish Server v5.1.0.

$ vi /opt/glassfish5/glassfish/domains/domain1/logs/server.log

・・・<途中省略>・・・

[2023-06-25T06:12:58.954+0000] [glassfish 5.1] [INFO] [NCLS-JMX-00025] [javax.enterprise.system.jmx] [tid: _Thr
eadID=58 _ThreadName=Thread-14] [timeMillis: 1687673578954] [levelValue: 800] [[
  SSLServerSocket /0.0.0.0:8686 and [SSL: ServerSocket[addr=/0.0.0.0,localport=8686]] created]]

[2023-06-25T06:12:59.891+0000] [glassfish 5.1] [INFO] [NCLS-JMX-00005] [javax.enterprise.system.jmx] [tid: _ThreadID=58 _ThreadName=Thread-14] [timeMillis: 1687673579891] [levelValue: 800] [[
  JMXStartupService has started JMXConnector on JMXService URL service:jmx:rmi://rhel8.reafnex.net:8686/jndi/rmi://rhel8.reafnex.net:8686/jmxrmi]]

SSLハンドシェイクのエラーは発生しなくなり、SSLサーバソケットがオープンされたことが確認できました。

まとめ

いかがでしたでしょうか。

今回は、GlassFish 5.1.0の構築テストの際に遭遇したSSLハンドシェイクのエラーの対策方法について紹介しました。

直接の原因は、GlassFish 5.1.0がサポートしているSSL 3.0とTLS 1.0の暗号化プロトコルが、RHEL 8ではデフォルトで利用できなくなっていたためでした。

そのため、OS側のJavaコンフィグの設定でSSL 1.0を利用可能にすることで、GlassFish 5.1.0のSSLハンドシェイクのエラーを回避することができました。

本来であれば、GlassFishがサポートしているSSL 3.0とTLS 1.0の両方を利用できるようにした方がいいのではという意見もあるかもしれませんが、現時点(2023年6月時点)においては、サイバーセキュリティに関する脆弱性の観点からSSL 3.0及びTLS 1.0は利用せず、TLS1.2以上を利用することが推奨されています。

しかしながら、一部のレガシーなアプリケーションやシステムでは、まだTLS 1.0やTLS 1.1を使用している場合もありますので、セキュリティの脆弱性に対するリスクなどを総合的に判断すると、GlassFish 5.1.0を動作させるサーバでのみTSL 1.0を利用可能とするシステム運用が考えられます。

なお、SSL 3.0のさセキュリティの脆弱性は、影響範囲やリスクが大きいため使用しない方がよいでしょう。

ご自身が利用又は管理しているシステムのセキュリティ運用条件に照らして、対策を検討してみてください。

なお、今回ご紹介したGlassFish 5.1.0のSSLハンドシェイクの対策方法については、当方の個人的な実験と見解に基づくものであり、この情報を利用する場合は、利用者の独自の判断と責任の下で行ってください。本情報の利用により生じた損害等に対して、当方は一切の責任を負いませんことご容赦ください。

参考になれば幸いです。

システムのお悩みについてご相談ください

本サイトの掲載内容に関するお問い合わせは、こちらから承ります。
SOHOのシステム運用管理に関するお悩みごとについて、なんでもお気兼ねなくご相談ください。
現役システムエンジニアのスタッフが、ボランティアでご相談にご対応させていただきます。