TLS:どの暗号スイートを選んだらいいのか?
2025-10-12時点
よく見かける暗号スイートの記号(Cipher String, 暗号化方式指定用文字列)は OpenSSL のライブラリによるもの。
(記号は 3.0 からmaster まで変化なし)
Cipher String は3.0以降消えているものがある。また、マニュアルにはあっても実装がないものがある。
(ソースにはあってもコンパイルオプションなどで除外されている)
困ったことに、アプリケーションごとにデフォルトの設定が異なっている上に、その設定の根拠がどこにも書かれていない。
アプリケーション製作者によって場当たり的に設定されてしまっていて、みんなよくわからないままそのデフォルト設定のままで運用しているのが現状。
さらにWeb上には古い説明が残っているために、その説明を鵜呑みにしてそのまま設定しているのが現状。
(OpenSSL 側で現在安全ではないとされるものをデフォルトで削っておけばいいと思うのだが、どうしてそうなっていないのだろう?)
RHEL 系では crypto-policies でシステムで統一的に設定できるようになったらしい。
Debian 系にはない。
ここでは、以下を推奨としている模様。
ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305
とりあえず、現状ではこれでよさげ
testssl.sh で互換性を確認して問題がない
Dovecot で Android 系が失敗しているが原因不明(ALLにしても失敗する。Dovecot の内部処理に問題がありそう。)
dhparam を作成
今は特に設定しなくても、自動的に ffdhe2048 などが選ばれる模様。
dhparam は現在は 2048 bit で生成する。(もう 3072, 4096bit の方がいいかも?)
$ sudo openssl dhparam -out /etc/ssl/dhparam 2048
テストのために testssl.sh を用意
docker がインストールされているなら
$ docker run --rm -ti drwetter/testssl.sh
Nginx
code:nginx.conf
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
ssl_dhparam /etc/ssl/dhparam.pem;
確認
$ ./testssl.sh your.domain
Postfix
本来は tls_medium_cipherlist を書き換えるべきではないが、仕組み上、そうするしかないので上書きする。
code:main.cf
# サーバー側の優先順位を使う
tls_preempt_cipherlist = yes
tls_medium_cipherlist = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305
# 相手が対応しているならTLSを使う
smtpd_tls_security_level = may
# may の場合は、smtpd_tls_mandatory_* は使用されない。encrypt の場合のみ
smtpd_tls_mandatory_protocols = >= TLSv1.2
smtpd_tls_mandatory_ciphers = medium
smtpd_tls_protocols = >= TLSv1.2
smtpd_tls_ciphers = middle
# smtpd_tls_dh1024_param_file = /etc/ssl/dhparam.pem
# smtpd_tls_session_cache_database = btree:/var/lib/postfix/smtpd_scache
# 相手が対応しているならTLSを使う
smtp_tls_security_level = may
# may の場合は、smtp_tls_mandatory_* は使用されない。encrypt の場合のみ
smtp_tls_mandatory_protocols = >= TLSv1.2
smtp_tls_mandatory_ciphers = medium
smtp_tls_protocols = >= TLSv1.2
smtp_tls_ciphers = middle
# smtp_tls_session_cache_database = btree:/var/lib/postfix/smtp_scache
postfix 3.9 以降、smtpd_tls_dh1024_param_file は設定しないのが正しい設定となった。以下のようなメッセージが出てくる。
postfix[19582]: /usr/sbin/postconf: warning: /etc/postfix/main.cf: support for parameter "smtpd_tls_dh1024_param_file" will be removed; instead, do not specify (leave at default)
確認
$ ./testssl.sh -t smtp your.domain:smtp
$ ./testssl.sh your.domain:smtps
$ ./testssl.sh -t your.domain:submission
$ ./testssl.sh your.domain:submissions
Dovecot
2.4 以降
/etc/dovecot/local.conf の方がいいのかも。
/etc/dovecot/conf.d/10-ssl.conf
code:10-ssl.conf
ssl = yes
ssl_min_protocol = TLSv1.2
ssl_server_prefer_ciphers = server
ssl_cipher_list = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305
ssl_server_dh_file = /etc/ssl/dhparam.pem
$ ./testssl.sh -t pop3 your.domain:pop3
$ ./testssl.sh your.domain:pop3s
$ ./testssl.sh -t imap your.domain:imap
$ ./testssl.sh your.domain:imaps
/icons/hr.icon
以下、色々調べた時のメモ
HTTP/2 では Appendix A.  TLS 1.2 Cipher Suite Black List というリストがあり、ブロック可能とされている。
IPA の「推奨セキュリティ設定」に挙げられている組み合わせでもブロックされるものがある。
TLS 1.2 未満(SSLv2, SSLv3, TLSv1.0, TLSv1.1)は基本的には禁止する。
(TLS 1.2 未満は既に過去の遺物なので、どうしても接続できない場合にのみ対応する)
TLS 1.2 では、鍵交換、署名、暗号化、メッセージ認証(ハッシュ関数)の組み合わせをほぼ自由に設定できて混乱していた。
TLS 1.3 では暗号化とメッセージ認証だけで固定的な全5種類の組み合わせになった。
(後に増える可能性はあるがたぶんその時には TLS 1.4 になってそう)
TLS_AES_128_GCM_SHA256
TLS_AES_256_GCM_SHA384
TLS_CHACHA20_POLY1305_SHA256
TLS_AES_128_CCM_SHA256
TLS_AES_128_CCM_8_SHA256
鍵交換と署名はここで設定するわけではないというだけで選択肢としては残っているらしい。
危殆化したものは既に外されているので問題はない模様。
OpenSSL 3.5.1 では、以下3種類が有効になっていた。
TLS_AES_128_GCM_SHA256
TLS_AES_256_GCM_SHA384
TLS_CHACHA20_POLY1305_SHA256
(コンパイルオプションで意図的に有効化はできるのかも?)
code:console
$ openssl ciphers -v 'aGOST'
Error in cipher list
40072EE32C7F0000:error:0A0000B9:SSL routines:SSL_CTX_set_cipher_list:no cipher match:../ssl/ssl_lib.c:3409:
エラーにはなっているが、これは OpenSSL のコマンド上のの問題なので、アプリケーションで '!aGOST' などとしても特に問題はない。
以下、存在しなかったものはあえて除外条件を追加で書く必要はなさそう。
(OpenSSL 3.5.1 による)
code:txt
LOW
kDHr
kDHd
kDH
aDH
3DES
DES
RC4
RC2
IDEA
SEED
aGOST
aGOST01
kGOST
GOST94
GOST89MAC
OpenSSL の Cipher String の根本的な設計の問題は、「安全な個別要素の組み合わせ」を設定できない(=個別要素のブラックリスト方式にしかできない)ことで、そうなると、自力で全部の暗号化方式を並べるしか方法がなくなる。
(TLSv1.3 からはちょっと事情が違う。)
IPAのガイドラインに沿って設定無効化すべきもので OpenSSL で該当する物を拾っていくと
鍵交換
kDH(非存在)
ECDH (ECDHEは良いとされているので、このあたりどうもよくわからない)
署名
kGOST(非存在)
ブロック暗号
RC2(非存在)
EXPORT(非存在)
IDEA
DES(非存在)
3DES(非存在)
ARIA
SEED
ストリーム暗号
RC4(非存在)
ハッシュ関数
MD5
どこに置くべきかいまいちわからないもの
GOST89MAC
GOST94
以下、少なくとも OpenSSL 3.5.1 の Cipher String には存在していない
SM2
SM3
SM4
RFC 5830 GOST 28147-89: Encryption, Decryption, and Message Authentication Code (MAC) Algorithms
RFC 5831 GOST R 34.11-94: Hash Function Algorithm
Updated by 6986
RFC 7091 GOST R 34.10-2012: Digital Signature Algorithm
RFC 6986 GOST R 34.11-2012: Hash Function
RFC 8891 GOST R 34.12-2015: Block Cipher "Magma"
RFC 7801 GOST R 34.12-2015: Block Cipher "Kuznyechik"
CTR_OMAC
RFC 9189  GOST Cipher Suites for Transport Layer Security (TLS) Protocol Version 1.2
IPA のガイドライン、デファクトスタンダードである OpenSSL 基準で書くしかないのだから、OpenSSL の Cipher String でどうなるべきかをばっちり書くべきだと思うんだが。
IPA TLS暗号設定ガイドライン(Ver3.1.1)では以下を推奨している。
https://gyazo.com/325391fff87d41ac22ec790b96adb3a4
以下を禁止している。
https://gyazo.com/fb4b462773b88006e3dd86435a28675b
https://gyazo.com/525f8e541bde626bc6da83889f44c763
色々条件があるので、詳細は原本を確認のこと。
どの暗号が選択肢になるのかの確認方法
$ openssl ciphers -v '文字列'
とにかく全部見る
$ openssl ciphers -v 'ALL:eNULL'
k* は鍵交換に使う場合
a* は署名に使う場合
e* は暗号化に使う場合
@STRENGTH があると、そこまでのリストを強度順に並べ替えてくれる。
(書かれた順で優先順位を付けることもできるが、普通の人には無理すぎる)
少なくとも HIGH を書く。
次に、その中から不要な組み合わせを除外する。
鍵交換では、DH, ECDH がダメで、DHE, ECDHE が望ましい。
OpenSSL では、kDHr, kDHd, kDH, 
postfix のデフォルトの組み合わせ (Ver.3.10)
確認する場合には以下のようにする。
$ sudo postconf -d | grep cipherlist
このリストは直接書き換えるべきではない。
余計な暗号スイートは、 smtp_tls_exclude_ciphers など *_exclude_ciphers で指定して削る。
code:txt
tls_export_cipherlist =
tls_null_cipherlist = eNULL:!kDH:!kECDH:!aDSS:!MD5:!aNULL
tls_low_cipherlist =
tls_medium_cipherlist = aNULL:-aNULL:HIGH:MEDIUM:!SEED:!IDEA:!3DES:!RC2:!RC4:!RC5:!kDH:!kECDH:!aDSS:!MD5:+RC4:@STRENGTH
tls_high_cipherlist = aNULL:-aNULL:HIGH:!SEED:!IDEA:!3DES:!RC2:!RC4:!RC5:!kDH:!kECDH:!aDSS:!MD5:@STRENGTH
aNULL の後に -aNULL にしてあるのは、「一旦リストから削除するけど、後の設定に存在すれば追加する」という意味らしい。
単に aNULL だと aNULL 全部が入ってしまうがそれを避けたい(?)
意味があるのかと思ったが、やっぱり意味なさげ。
ARIA だけが余分なので、ARIA だけ除外すればよさげ?
残念ながら、メールサーバー、クライアントによってはTLSの設定ができていないケースがあるため、TLS の使用は may にする。
特定の送信先で指定できないか?
どのみち相手の対応次第なのでこちらからはどうしようもない。
code:main.cf
# サーバー側の優先順位を使う
tls_preempt_cipherlist = yes
# 相手が対応しているならTLSを使う
smtpd_tls_security_level = may
# may の場合は、smtpd_tls_mandatory_* は使用されない。encrypt の場合のみ
# smtpd_tls_mandatory_protocols = >= TLSv1.2
# smtpd_tls_mandatory_ciphers = high
# smtpd_tls_mandatory_exclude_ciphers = ARIA
smtpd_tls_protocols = >= TLSv1.2
smtpd_tls_ciphers = high
smtpd_tls_exclude_ciphers = CBC,aNULL
smtpd_tls_dh1024_param_file = /etc/postfix/dhparam.pem
# smtpd_tls_session_cache_database = btree:/var/lib/postfix/smtpd_scache
# 相手が対応しているならTLSを使う
smtp_tls_security_level = may
# may の場合は、smtp_tls_mandatory_* は使用されない。encrypt の場合のみ
# smtp_tls_mandatory_protocols = >= TLSv1.2
# smtp_tls_mandatory_ciphers = high
# smtp_tls_mandatory_exclude_ciphers = ARIA
smtp_tls_protocols = >= TLSv1.2
smtp_tls_ciphers = high
smtp_tls_exclude_ciphers = CBC,aNULL
# smtp_tls_session_cache_database = btree:/var/lib/postfix/smtp_scache
ARIA は CBC に含まれているので CBC だけで除外されるもよう。
CBC を除外すると、CCM, CCM_8 も除外されてしまうので範囲としては大きすぎか?
マニュアルを見ると、*_exclude_ciphers にはカンマ区切りでエクスクラメーションなしで cipher string を書くらしい。
セッションキャッシュは TLS1.3 ではもう不要説がある。ほとんど改善しないらしい。(どちらかというとDoSで攻撃される要因になるか?)
smtpd_use_tls, smtp_use_tls は古いオプション。ごちゃまぜに書くな。マニュアルを確認しろ。
submission で AUTH を受け付ける時に TLS を必須にする。
master.cf で submission のオプションに smtpd_tls_auth_only = yes を追加する。(デフォルトでそうなってるはず)
nginx
dhparam を3072bitで作成する。
$ sudo openssl dhparam -out /etc/nginx/dh2048.pem 3072
今は ssl_protocols TLSv1.2 TLSv1.3; がデフォルトだから明示は不要かもしれない。
ssl_ciphers はデフォルトで HIGH:!aNULL:!MD5 になっている。
code:nginx.conf
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers HIGH:!aNULL:!MD5:!CBC;
ssl_dhparam /etc/nginx/dhparam.pem;
デフォルトは ssl_ciphers HIGH:!aNULL:!MD5;
CBCを無効にするだけで、よさそう。
ssl_session_cache はもう不要らしい。TLSv1.3 ではほとんど効率が上がらないらしい。
Dovecot
2.4 から大幅に設定方法が変わった。
testssl.sh だと、なぜか Android クライアントが接続できなくなっている。色々やったが原因不明
(Dovecot が勝手に何か制約付けてる?)
code:/etc/dovecot/conf.d/10-ssl.conf
ssl=yes
ssl_min_protocol = TLSv1.2
#ssl_cipher_list = ALL:!kRSA:!SRP:!kDHd:!DSS:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK:!RC4:!ADH:!LOW@STRENGTH ssl_ciphers HIGH:!aNULL:!MD5:!CBC;
ssl_server_prefer_ciphers = server
TLS証明書
確認
testssl.sh を使うのが簡単
curl でダウンロードできるかのように書いてあるができなかった。
参考
TLS暗号設定ガイドライン 安全なウェブサイトのために(暗号設定対策編)
これからのメールセキュリティ(暗号編)
HTTP/2を利用する際はCipher Suiteを正しく設定しよう
メモ
OpenSSL