Rocky Linux 8のSSHサーバーでCBCとSHA1を無効化する方法

RHEL8系OS共通ですので、下記のLinuxでも使えると思います。ただし、検証は**Rocxy Linux 8のみ**で行っていますので、他でうまくいかないと言う場合は確認しますのでコメントください。

- RedHat Enterprise Linux 8
- CentOS Stream 8
- ~~CentOS 8~~ (2021年12月31日サポート終了)
- Oracle Linux 8
- AlmaLinux 8
- **Rocky Linux 8**

**【注意】**この手順では最終的にMACと署名を除いてSHA1をシステム全体で無効にします。SSHサーバー以外のサービスにも影響がでる場合があります。ただし、MACと署名ではSHA1使用は可能であるため、HTTPS等のSSL/TLS通信についてはほとんど影響が無いはずです。

## SSHサーバー(sshd)の脆弱な暗号アルゴリズム

RHEL8系の標準設定のサーバーに対してNessusでスキャンを行うと次の二つのプラグインが引っかかります。

- [70658](https://jp.tenable.com/plugins/nessus/70658) SSH サーバーの CBC モード暗号が有効
- [153953](https://jp.tenable.com/plugins/nessus/153953) SSHの弱い鍵交換アルゴリズムが有効

一つ目はCBCモード暗号を使用しているというものです。SSHのプロトコルとCBCモードの組合せで、極めて低い確率で一部のデータを平文で取得できるという脆弱性が発見されています。

二つ目は弱い鍵交換アルゴリズムが有効であるというものです。デフォルトで有効なのは``diffie-hellman-group-exchange-sha1``のみですが、この鍵交換アルゴリズムはグループが不定であり、サイズ小さいグループが選ばれた場合は十分なセキュリティを提供できません。

脆弱性の指摘に対応するには、CBCモードを``diffie-hellman-group-exchange-sha1``を無効にすればいいのですが、話はそう簡単にいきません。

## デフォルト設定の確認

RHEL8系のでデフォルトでは次の暗号モードと鍵交換アルゴリズムが使用されています。

- 暗号モード Ciphers
    - `aes256-gcm@openssh.com`
    - `chacha20-poly1305@openssh.com`
    - `aes256-ctr`
    - **`aes256-cbc`**
    - `aes128-gcm@openssh.com`
    - `aes128-ctr`
    - **`aes128-cbc`**
- 鍵交換アルゴリズム KexAlgorithms
    - `curve25519-sha256`
    - `curve25519-sha256@libssh.org`
    - `ecdh-sha2-nistp256`
    - `ecdh-sha2-nistp384`
    - `ecdh-sha2-nistp521`
    - `diffie-hellman-group-exchange-sha256`
    - `diffie-hellman-group14-sha256`
    - `diffie-hellman-group16-sha512`
    - `diffie-hellman-group18-sha512`
    - **`diffie-hellman-group-exchange-sha1`**
    - _`diffie-hellman-group14-sha1`_

太字がプラグインで脆弱であると指摘されたアルゴリズムです。根拠資料では``diffie-hellman-group14-sha1``は互換性のために完全に非推奨とはされていませんが、可能であれば無効にすることが推奨されていますので、今回の手順ではSHA1を使用する全ての鍵交換アルゴリズムを無効にしようと思います。

さて、これらを無効にするにはどうしたらいいのでしょうか？以前のバージョンや他のディストリビューションで有れば``/etc/ssh/sshd_config``で``Cipher``や``KexAlgorithms``を設定すると言う方法ができました。しかし、RHEL8系ではいくら``sshd_config``を変更しても、反映されません。なぜなら、[暗号化ポリシー(crypto-policies)](https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/8/html/security_hardening/using-the-system-wide-cryptographic-policies_security-hardening)という仕組みによって制御されているからです。。

``ps auwx | grep sshd``と実行してみるとわかりますが、``sshd``の実行する時に非常に長いオプションが付いています。そう、ここで、``Cipher``や``KexAlgorithms``が指定されているため、``sshd_config``の設定は無視されてしまうのです。では、このオプションはどこから来るかというと、``/lib/systemd/system/sshd.service``をみると``/etc/crypto-policies/back-ends/opensshserver.config``と言うのを読み込んでいるのがわかります。そう、この中で、暗号に関するオプションが指定されているのです。

この``opensshserver.config``が何かというと、それが先程行った暗号化ポリシーです。システム全体の暗号化ポリシー設定に従って、``opensshserver.config``が自動的に生成され、指定された暗号アルゴリズムのみを使用するようにしていると言うことです。

つまり、適切な暗号化ポリシーを設定すればいいと言うことになります。

## CBCとSHA1無効のためのポリシーの変更方法

暗号化ポリシーにはメインとなるポリシーとサブポリシーがあります。デフォルトは``DEFAULT``ポリシーで、サブポリシーはありません。これをより強い``FUTURE``ポリシーに変更しても``aes256-cbc``は無効化されません。また、``FUTURE``ポリシーではSHA1の署名も無効化されるため、自己署名証明書などSHA1で作成された証明書がエラーになる場合があります。標準で用意されているサブポリシーと組み合わせても、うまく解決することはできません。そこで、今回はカスタムサブポリシーを作成する方法で言います。

下記内容のカスタムサブポリシーファイル``SEC-SSH.pmod``を作成し、カスタムサブポリシー置き場である``/etc/crypto-policies/policies/modules``に置きます。

```/etc/crypto-policies/policies/modules/SEC-SSH.pmod
# Secure SSH
ssh_cipher = -AES-256-CBC -AES-128-CBC -3DES-CBC
hash = -SHA1
```

あとは、次のコマンドを実行するだけです。

```
sudo update-crypto-policies --set DEFAULT:SEC-SSH
```

``sshd.service``を再起動してみてください。``ps auwx | grep sshd``でオプションにCBCを使用した暗号モードとSHA1を使用した鍵交換アルゴリズムが無い事を確認できると思います。

なお、この方法ではSSH以外にも**システム全体でSHA1が無効化**されますので、一度再起動して、他サービスに影響が無いかを確認してください。

## 解説とかその他の方法とか

``ssh_cipher``はSSHのみに関する暗号モードの指定です(``3DES-CBC``は``LEGACY``ポリシーの時に有効になるため、合わせて無効にしています)。``hash``は使用するハッシュ関数アルゴリズムの指定ですが、MACと署名については影響を与えません。

SHA1全てを無効にする代わりに、MODPグループ不定の鍵交換アルゴリズムを無効にする方法もあります。

```
arbitrary_dh_groups = 0
```

この場合は、``diffie-hellman-group14-sha1``が無効化されず、代わりに``diffie-hellman-group-exchange-sha256``が無効化されます。互換性のために``diffie-hellman-group14-sha1``がどうしても必要という場合は、この方法でもある程度のセキュリティを確保することは可能です。

残念ながら、暗号化ポリシーの設定で``diffie-hellman-group-exchange-sha1``だけを無効にする方法は見つけられませんでした。どうしても必要という場合は、``/etc/sysconfig/sshd``で下記のように``CRYPTO_POLICY=``のコメントアウトを外してください。

```/etc/sysconfig/sshd
CRYPTO_POLICY=
```

暗号化ポリシーによる制御か無効になるため、``sshd_config``で`Cipher``や``KexAlgorithms``を直接設定することで特定アルゴリズムの無効化が可能になります。

## 【おまけ】``diffie-hellman-group-exchange-sha1``は本当に無効にする必要があるのか？

``diffie-hellman-group-exchange-sha1``はMODPグループが不定のためサイズが小さいMODPグループが選ばれる可能性があります。もし、1024ビットのMODPグループが選ばれた場合、1024ビットのMODPグループを使用する``diffie-hellman-group1-sha1``と同じぐらい脆弱であると言うことです。``diffie-hellman-group1-sha1``は1024ビットとSHA1という小さいサイズの組合せのため非推奨となっています。対して、``diffie-hellman-group14-sha1``は2048ビットのMODPグループを使用するため、2048ビットとSHA1の組合せはまだましと言うことで、互換性のために許されるとなっています。では、``diffie-hellman-group-exchange-sha1``で2048ビット以上のMODPグループしか使用されない場合はどうなのでしょうか？一番小さい2048ビットのMODPグループが使用されたとしても、安全性は``diffie-hellman-group14-sha1``と言うことができます。

つまり、根拠資料の指針に沿えば、2048ビット以上のMODPグループしか選ばれないなら、``diffie-hellman-group-exchange-sha1``でも、``diffie-hellman-group14-sha1``と同様に互換性のために許されると考えられます。MODPグループは``/etc/ssh/moduli``に全て書かれており、ここから選ばれます。5番目のフィールドがサイズ(2048ビットなら2047と1小さい値)になっています。そこで、ここにサイズが2048ビット未満があるか確認してみましょう。

```
awk '{ if ($5 < 2047) print }' /etc/ssh/moduli
```

``moduli``をカスタマイズしていないデフォルト状態であれば、存在しないはずです。つまり、**デフォルト状態でも``diffie-hellman-group-exchange-sha1``を無効にする必要は無い**と言えるかも知れません。なお、MODPグループのリストはリモートから取得することは不可能なため、Nessusのプラグインはサイズが小さいグループが存在することを前提に検出するしかありません。

最後に、CBCも低確率かつ少量の平文なので、そまで神経質になって無効にする必要があるのかと言われると微妙だと言わざるを得ません。ただ、将来を考えたら、CBCもSHA1も今のうちに無効にしておいて、対応していない製品や機器などをあぶり出しておくというのがいいかもしれません。[^1]

[^1]: 実際に、CBCとSHA1を無効にした後、古いバージョンのFileZillaを使用していたユーザーから接続できないという問い合わせがありました。PCに入っているクライアントソフトでも定期的にアップデートしておいて欲しいところです。