Apacheの暗号化スイートの設定

2022年6月17日

前提

書くこと/書かないこと

ApacheのSSL設定のあるべき姿を考えます。
個人の意見ですので建設的なご意見歓迎します。

環境

AlmaLinux 8.6 ※CentOS8代替OS

Apache/2.4.37 (AlmaLinux)

OpenSSL 1.1.1k FIPS 25 Mar 2021

さくっと

ssl.confのSSLCipherSuiteとSSLProxyCipherSuiteを下記のとおり設定します。

SSLCipherSuite "ECDHE+AESGCM:DHE+aRSA+AESGCM:ECDHE+AESCCM:DHE+aRSA+AESCCM:ECDHE+CHACHA20:DHE+aRSA+CHACHA20:+AES128:+DHE"
SSLCipherSuite TLSv1.3 "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256"

SSLProxyCipherSuite "ECDHE+AESGCM:DHE+aRSA+AESGCM:ECDHE+AESCCM:DHE+aRSA+AESCCM:ECDHE+CHACHA20:DHE+aRSA+CHACHA20:+AES128:+DHE"
SSLProxyCipherSuite TLSv1.3 "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256"

設定したらapacheを再起動すると設定が反映されます。

systemctl restart httpd.service

こってりと

デフォルト設定でのSSL Labsによる評価結果

問題認識の背景にあるのは、SSL Labsによる評価結果です。

[SSL Labs : SSL Server Test] https://www.ssllabs.com/ssltest/

上記の通り、総合評価がBということで改善余地がある状態ですので、設定を見直していきたいと思います。

改善のポイント

レポートのCipher Suites見ると、複数の弱い暗号方式が許可される設定になっていることが確認できます。

この設定は直接的にはssl.conf内の下記箇所によって制御されています。

#   SSL Cipher Suite:
#   List the ciphers that the client is permitted to negotiate.
#   See the mod_ssl documentation for a complete list.
#   The OpenSSL system profile is configured by default.  See
#   update-crypto-policies(8) for more details.
SSLCipherSuite PROFILE=SYSTEM
SSLProxyCipherSuite PROFILE=SYSTEM

改善方法としては、弱い暗号化スイートを使わないように設定を見直してあげれば良く、IPAでもかなり具体的に説明していますので、これを参考にして具体的に定義するのが一つのやり方だと思います。

(偉大な先人)

https://www.ipa.go.jp/security/ipg/documents/tls_cipher_suite_config_20200707.pdf

「PROFILE=SYSTEM」とは何か

私が腹落ちできなかったのが上記になります。
調べたところ、apacheのmod_sslはopensslの設定を参照していることがわかりましたので、SSLCipherSuiteを直接変更して具体的な設定に変えるということは、OpenSSLのプロファイルのを使わずに直接指定することを意味することになります。

今回の環境でOpenSSLのPROFILEを確認すると以下のようになっていましたので、apacheの初期設定はこれを読み込んでいることになります。

# openssl ciphers -v 'PROFILE=SYSTEM'
TLS_AES_256_GCM_SHA384  TLSv1.3 Kx=any      Au=any  Enc=AESGCM(256) Mac=AEAD
TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any      Au=any  Enc=CHACHA20/POLY1305(256) Mac=AEAD
TLS_AES_128_GCM_SHA256  TLSv1.3 Kx=any      Au=any  Enc=AESGCM(128) Mac=AEAD
TLS_AES_128_CCM_SHA256  TLSv1.3 Kx=any      Au=any  Enc=AESCCM(128) Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=CHACHA20/POLY1305(256) Mac=AEAD
ECDHE-RSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH     Au=RSA  Enc=CHACHA20/POLY1305(256) Mac=AEAD
ECDHE-ECDSA-AES256-CCM  TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESCCM(256) Mac=AEAD
ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(128) Mac=AEAD
ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AESGCM(128) Mac=AEAD
ECDHE-ECDSA-AES128-CCM  TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESCCM(128) Mac=AEAD
ECDHE-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AES(128)  Mac=SHA256
ECDHE-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AES(128)  Mac=SHA256
ECDHE-ECDSA-AES256-SHA  TLSv1 Kx=ECDH     Au=ECDSA Enc=AES(256)  Mac=SHA1
ECDHE-RSA-AES256-SHA    TLSv1 Kx=ECDH     Au=RSA  Enc=AES(256)  Mac=SHA1
ECDHE-ECDSA-AES128-SHA  TLSv1 Kx=ECDH     Au=ECDSA Enc=AES(128)  Mac=SHA1
ECDHE-RSA-AES128-SHA    TLSv1 Kx=ECDH     Au=RSA  Enc=AES(128)  Mac=SHA1
AES256-GCM-SHA384       TLSv1.2 Kx=RSA      Au=RSA  Enc=AESGCM(256) Mac=AEAD
AES256-CCM              TLSv1.2 Kx=RSA      Au=RSA  Enc=AESCCM(256) Mac=AEAD
AES128-GCM-SHA256       TLSv1.2 Kx=RSA      Au=RSA  Enc=AESGCM(128) Mac=AEAD
AES128-CCM              TLSv1.2 Kx=RSA      Au=RSA  Enc=AESCCM(128) Mac=AEAD
AES256-SHA256           TLSv1.2 Kx=RSA      Au=RSA  Enc=AES(256)  Mac=SHA256
AES128-SHA256           TLSv1.2 Kx=RSA      Au=RSA  Enc=AES(128)  Mac=SHA256
AES256-SHA              SSLv3 Kx=RSA      Au=RSA  Enc=AES(256)  Mac=SHA1
AES128-SHA              SSLv3 Kx=RSA      Au=RSA  Enc=AES(128)  Mac=SHA1
DHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=DH       Au=RSA  Enc=AESGCM(256) Mac=AEAD
DHE-RSA-CHACHA20-POLY1305 TLSv1.2 Kx=DH       Au=RSA  Enc=CHACHA20/POLY1305(256) Mac=AEAD
DHE-RSA-AES256-CCM      TLSv1.2 Kx=DH       Au=RSA  Enc=AESCCM(256) Mac=AEAD
DHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=DH       Au=RSA  Enc=AESGCM(128) Mac=AEAD
DHE-RSA-AES128-CCM      TLSv1.2 Kx=DH       Au=RSA  Enc=AESCCM(128) Mac=AEAD
DHE-RSA-AES256-SHA256   TLSv1.2 Kx=DH       Au=RSA  Enc=AES(256)  Mac=SHA256
DHE-RSA-AES128-SHA256   TLSv1.2 Kx=DH       Au=RSA  Enc=AES(128)  Mac=SHA256
DHE-RSA-AES256-SHA      SSLv3 Kx=DH       Au=RSA  Enc=AES(256)  Mac=SHA1
DHE-RSA-AES128-SHA      SSLv3 Kx=DH       Au=RSA  Enc=AES(128)  Mac=SHA1
PSK-AES256-GCM-SHA384   TLSv1.2 Kx=PSK      Au=PSK  Enc=AESGCM(256) Mac=AEAD
PSK-CHACHA20-POLY1305   TLSv1.2 Kx=PSK      Au=PSK  Enc=CHACHA20/POLY1305(256) Mac=AEAD
PSK-AES256-CCM          TLSv1.2 Kx=PSK      Au=PSK  Enc=AESCCM(256) Mac=AEAD
PSK-AES128-GCM-SHA256   TLSv1.2 Kx=PSK      Au=PSK  Enc=AESGCM(128) Mac=AEAD
PSK-AES128-CCM          TLSv1.2 Kx=PSK      Au=PSK  Enc=AESCCM(128) Mac=AEAD
PSK-AES256-CBC-SHA      SSLv3 Kx=PSK      Au=PSK  Enc=AES(256)  Mac=SHA1
PSK-AES128-CBC-SHA256   TLSv1 Kx=PSK      Au=PSK  Enc=AES(128)  Mac=SHA256
PSK-AES128-CBC-SHA      SSLv3 Kx=PSK      Au=PSK  Enc=AES(128)  Mac=SHA1
DHE-PSK-AES256-GCM-SHA384 TLSv1.2 Kx=DHEPSK   Au=PSK  Enc=AESGCM(256) Mac=AEAD
DHE-PSK-CHACHA20-POLY1305 TLSv1.2 Kx=DHEPSK   Au=PSK  Enc=CHACHA20/POLY1305(256) Mac=AEAD
DHE-PSK-AES256-CCM      TLSv1.2 Kx=DHEPSK   Au=PSK  Enc=AESCCM(256) Mac=AEAD
DHE-PSK-AES128-GCM-SHA256 TLSv1.2 Kx=DHEPSK   Au=PSK  Enc=AESGCM(128) Mac=AEAD
DHE-PSK-AES128-CCM      TLSv1.2 Kx=DHEPSK   Au=PSK  Enc=AESCCM(128) Mac=AEAD
DHE-PSK-AES256-CBC-SHA  SSLv3 Kx=DHEPSK   Au=PSK  Enc=AES(256)  Mac=SHA1
DHE-PSK-AES128-CBC-SHA256 TLSv1 Kx=DHEPSK   Au=PSK  Enc=AES(128)  Mac=SHA256
DHE-PSK-AES128-CBC-SHA  SSLv3 Kx=DHEPSK   Au=PSK  Enc=AES(128)  Mac=SHA1
ECDHE-PSK-CHACHA20-POLY1305 TLSv1.2 Kx=ECDHEPSK Au=PSK  Enc=CHACHA20/POLY1305(256) Mac=AEAD
ECDHE-PSK-AES256-CBC-SHA TLSv1 Kx=ECDHEPSK Au=PSK  Enc=AES(256)  Mac=SHA1
ECDHE-PSK-AES128-CBC-SHA256 TLSv1 Kx=ECDHEPSK Au=PSK  Enc=AES(128)  Mac=SHA256
ECDHE-PSK-AES128-CBC-SHA TLSv1 Kx=ECDHEPSK Au=PSK  Enc=AES(128)  Mac=SHA1

なお、OpenSSLのプロファイルにはいくつか種類があり、初期値はDEFAULTですが、他にもいくつか種類があります。

Redhatのページに記載があったので転載します。

What policies are provided?

Four policies are provided under the names “LEGACY”, “DEFAULT”, “FUTURE” and “FIPS”. They are summarized and described in the table below.

https://access.redhat.com/articles/3642912
Policy nameDescription
LEGACYThis policy ensures maximum compatibility with legacy systems; it is less secure and it includes support for TLS 1.0, TLS 1.1, and SSH2 protocols or later. The algorithms DSA, 3DES, and RC4 are allowed, while RSA and Diffie-Hellman parameters are accepted if larger than 1023-bits.
DEFAULTThe DEFAULT policy is a reasonable default policy for today’s standards, aimed for a balance between usability and security. It allows the TLS 1.2 and 1.3 protocols, as well as IKEv2 and SSH2. The RSA and Diffie-Hellman parameters are accepted if larger than 2047-bits.
FUTUREA conservative security level that is believed to withstand any near-term future attacks. The purpose of the policy is for testing infrastructure and applications for their readiness for future strengthening of requirements. The policy is not supposed to be used for general purpose systems. This level does not allow the use of SHA-1 in signature algorithms. The RSA and Diffie-Hellman parameters are accepted if larger than 3071-bits.
FIPSA level that conforms to the FIPS140-2 requirements. This policy is used internally by the fips-mode-setup tool which can switch the RHEL system into FIPS140 mode.

現在のポリシーは下記コマンドで確認できます。

# update-crypto-policies --show
DEFAULT

DEFAULTですね。

ポリシーの変更は"/etc/crypto-policies/config"を編集し、コマンド: update-crypto-policiesを実行すると反映されます。

試しにポリシーをFUTUREに変えて、openssl ciphers -v 'PROFILE=SYSTEM’がどう変わるかを確認してみました。

まずはconfigをDEFAULTからFUTUREに変更して保存します。

FUTURE

次にポリシーを更新するコマンドを実行します。

# update-crypto-policies
Setting system policy to FUTURE
Note: System-wide crypto policies are applied on application start-up.
It is recommended to restart the system for the change of policies

FUTUREに変わりましたので、openssl ciphers -v 'PROFILE=SYSTEM’を確認します。

# openssl ciphers -v 'PROFILE=SYSTEM'
TLS_AES_256_GCM_SHA384  TLSv1.3 Kx=any      Au=any  Enc=AESGCM(256) Mac=AEAD
TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any      Au=any  Enc=CHACHA20/POLY1305(256) Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=CHACHA20/POLY1305(256) Mac=AEAD
ECDHE-RSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH     Au=RSA  Enc=CHACHA20/POLY1305(256) Mac=AEAD
ECDHE-ECDSA-AES256-CCM  TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESCCM(256) Mac=AEAD
DHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=DH       Au=RSA  Enc=AESGCM(256) Mac=AEAD
DHE-RSA-CHACHA20-POLY1305 TLSv1.2 Kx=DH       Au=RSA  Enc=CHACHA20/POLY1305(256) Mac=AEAD
DHE-RSA-AES256-CCM      TLSv1.2 Kx=DH       Au=RSA  Enc=AESCCM(256) Mac=AEAD
PSK-AES256-GCM-SHA384   TLSv1.2 Kx=PSK      Au=PSK  Enc=AESGCM(256) Mac=AEAD
PSK-CHACHA20-POLY1305   TLSv1.2 Kx=PSK      Au=PSK  Enc=CHACHA20/POLY1305(256) Mac=AEAD
PSK-AES256-CCM          TLSv1.2 Kx=PSK      Au=PSK  Enc=AESCCM(256) Mac=AEAD
DHE-PSK-AES256-GCM-SHA384 TLSv1.2 Kx=DHEPSK   Au=PSK  Enc=AESGCM(256) Mac=AEAD
DHE-PSK-CHACHA20-POLY1305 TLSv1.2 Kx=DHEPSK   Au=PSK  Enc=CHACHA20/POLY1305(256) Mac=AEAD
DHE-PSK-AES256-CCM      TLSv1.2 Kx=DHEPSK   Au=PSK  Enc=AESCCM(256) Mac=AEAD
ECDHE-PSK-CHACHA20-POLY1305 TLSv1.2 Kx=ECDHEPSK Au=PSK  Enc=CHACHA20/POLY1305(256) Mac=AEAD

SSLv3など古いプロトコルがなくなり、AES-128など弱いとされるアルゴリズムも使えなくなりました。

ただし、安全性が高まったのでこれで良しとするかというと、歓迎すべきユーザがどんな環境からアクセスしてくるかわからないブログサイトなどでこれをやってしまうと、アクセスできないユーザが増えてしまいます。

先のRedhatのドキュメントにも"The policy is not supposed to be used for general purpose systems."と書かれており、これがユーザの利便性を損なわない特定のシステム以外での利用は想定していないようです。

そのため、ポリシーはDEFAULTのままで運用するのが正しい形になると理解しました。

(偉大な先人)

https://wiki.bit-hive.com/tomizoo/pg/crypto%20policy

ついでにOpenSSLのことを考える

OpenSSLはLinuxでは非常に重要なライブラリの一つで、脆弱性の研究も活発であり、高頻度で更新が繰り返されています。
下記は2021年以降の更新履歴ですが、6回も更新版がリリースされていることがわかります。
それだけ脆弱性が発見され、対策が講じられていることを意味しますので、Webサービスを運営する場合も可能な限り最新版を維持することが望ましいと思います。

OpenSSL 1.1.1o [3 May 2022]
OpenSSL 1.1.1n [15 Mar 2022]
OpenSSL 1.1.1m [14 Dec 2021]
OpenSSL 1.1.1l [24 Aug 2021]
OpenSSL 1.1.1k [25 Mar 2021]
OpenSSL 1.1.1j [16 Feb 2021]

今回の環境にインストールされているバージョンは1.1.1kですので、約1年前にリリースされたバージョンですが、現時点で標準リポジトリからインストールできるバージョンとしてはこれが最新になります。

OpenSSLは現在、1.1.1系のマイナーアップデートを続けつつも、最新メジャーバージョンとして3.0系がリリースされています。

できればOpenSSL 3系を使うべきなのでしょうが、OpenSSLを使う側のapacheなどにおいても、標準リポジトリが提供するバージョンではOpenSSL 3系には対応していません。

そのため、OpenSSL 3系を使うためには、apacheをソースから構成してインストールすることが必要になるため、手間とハードルが上がります。

ソースインストール自体は一度やり方を覚えてしまえば、そこまで難しくはないのですが、dnf updateのようなお手軽な更新方法がなくなるので、アップデートの労力を割くことができ、かつその価値があるシステムを守るためには有効な方法だと思いますが、すべてのWebサーバでそこまでやれるかというと難しいです。

個人的にはまだここに対する正解は見いだせてないですが、OS上に直接apacheをインストールするような形だとどうしても難しいので、Dockerを使ってソースからインストールしたapacheを用意し、バージョンを変えるときにはコンテナの入れ替えで済むような形を目指すのが一案かなと思います。

Dockerでソースインストールをしたことがないので、時間ができたらトライしてみようと思いますが、答えや別のアイディアをお持ちの方がいたら教えてください。

結局SSLCipherSuiteはどうするか

以上つらつら考えてみると、OpenSSLの設定を踏襲せず、ssl.conf上で使いたい暗号化スイートだけを直接上書き指定するというのが、やはり合理的な方法に思えてきましたので、それを答えとすることにします。

SSLCipherSuiteの設定値

IPAでは「TLS暗号設定 暗号スイート令和2年7月 独立行政法人 情報処理推進機構 の設定例」を公開しており、その中に主要Webサーバでの推奨設定が記載されています。その中から高セキュリティ型を採用し、下記の通り設定することにします。

SSLCipherSuite "ECDHE+AESGCM:DHE+aRSA+AESGCM:ECDHE+AESCCM:DHE+aRSA+AESCCM:ECDHE+CHACHA20:DHE+aRSA+CHACHA20:+AES128:+DHE"
SSLCipherSuite TLSv1.3 "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256"

SSLProxyCipherSuite "ECDHE+AESGCM:DHE+aRSA+AESGCM:ECDHE+AESCCM:DHE+aRSA+AESCCM:ECDHE+CHACHA20:DHE+aRSA+CHACHA20:+AES128:+DHE"
SSLProxyCipherSuite TLSv1.3 "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256"

apacheを再起動した後に再度SSL Server Testを実施した結果、下記の通り、WEAKがゼロ件になりました。

ただし、暗号化スイートを絞ったことの副反応として、下記のように一部の古いOSやブラウザなどでTLSハンドシェイクに失敗する環境が出来てしまいました。

セキュリティを高めることで利用できなくなるユーザが生まれるリスクがあるので、設定する際にはその影響を考える必要があります。これは色々な考えがあるところですが、特別なSLAを結んでいるでもない限り、一部の利用者に配慮しすぎてシステム全体のリスクを高める方が拙いので、普通はこれで問題ないと考えます。

さて、肝心のSSL Server Testの再結果ですが、無事に総合評価が"A+"になりました。

あるセキュリティ設定が有効かどうかは時間とともに変わりますので、重要なサイトについては定期的な再評価が必要だと思います。