日和見 TLS(Opportunistic TLS)
概要
日和見 TLS(Opportunistic TLS) は、通信相手が TLS に対応していれば暗号化を行い、対応していなければ平文のまま通信を続行する暗号化方式です。RFC 7435(2014 年)で日和見セキュリティの一般的な概念が定義されており、SMTP における実装は RFC 3207(2002 年)の STARTTLS コマンドで規定されています。
日和見 TLS の設計思想は「暗号化できる場合は暗号化し、できない場合でも通信を止めない」というものです。メール配送の信頼性を最優先に置くため、TLS のネゴシエーションに失敗しても平文にフォールバックします。この方式は受動的な盗聴に対しては有効ですが、能動的な攻撃者(中間者攻撃)に対しては脆弱です。攻撃者がネットワーク経路上で TLS の能力通知を除去すれば、暗号化を迂回できます。
Google の透明性レポートによると、Gmail が送信するメールのうち TLS で暗号化される割合は 2024 年時点で約 91% に達しています。日和見 TLS の普及により、メールのトランスポート暗号化は大幅に改善しました。一方で、残りの約 9% は依然として平文で送信されており、ダウングレード攻撃への脆弱性も解消されていません。
仕組み
日和見 TLS は SMTP の EHLO 応答で STARTTLS の対応を確認し、対応していれば暗号化、非対応なら平文で通信を続行します。
SMTP における日和見 TLS の流れ
メールサーバー間の通信で日和見 TLS が動作するシーケンスは次の通りです。
- 送信側 MTA がポート 25 で受信側 MTA に TCP 接続する
- 受信側が
220バナーを返す - 送信側が
EHLOコマンドを送信する - 受信側が
250-STARTTLSを含む機能一覧を返す - 送信側が
STARTTLSコマンドを送信する - 受信側が
220 Ready to start TLSで応答する - TLS ハンドシェイクが成功し、以降の通信が暗号化される
ステップ 4 で 250-STARTTLS が返されなかった場合、送信側は TLS を開始せず平文のまま SMTP セッションを続行します。これが日和見 TLS の「日和見」たる所以です。
厳密な TLS との違い
日和見 TLS と厳密な TLS(Strict TLS)の違いは、暗号化に失敗した場合の動作です。
| 項目 | 日和見 TLS | 厳密な TLS |
|---|---|---|
| TLS 非対応時 | 平文で続行 | 通信を中断 |
| 証明書検証 | スキップする場合が多い | 必須 |
| ダウングレード耐性 | なし | あり |
| 配送の信頼性 | 高い | TLS 障害時に配送遅延 |
| 設定値の例(Postfix) | smtp_tls_security_level = may | smtp_tls_security_level = verify |
Postfix の may は日和見 TLS を意味します。相手が STARTTLS に対応していれば暗号化し、対応していなければ平文で送信します。verify や dane は厳密な検証を行い、TLS 接続に失敗した場合はメールの送信を保留します。
STARTTLS ストリッピング攻撃
日和見 TLS の最大の脆弱性は、STARTTLS ストリッピング攻撃に対する耐性がない点です。
攻撃者がネットワーク経路上に位置する場合、受信側サーバーの EHLO 応答から 250-STARTTLS の行を削除できます。送信側 MTA は相手が STARTTLS に対応していないと判断し、平文でメールを送信します。送信側にも受信側にもエラーは発生しないため、暗号化が無効化されたことに気付きにくい構造です。
正常な場合:
受信側 → 250-STARTTLS → 送信側(STARTTLS を開始)
ストリッピング攻撃:
受信側 → 250-STARTTLS → [攻撃者が除去] → 送信側(平文で続行)
日和見 TLS を補強する仕組み
日和見 TLS のダウングレード脆弱性を補うために、次の仕組みが標準化されています。
MTA-STS(RFC 8461)は、受信側ドメインが HTTPS 経由でポリシーファイルを公開し、「このドメインへのメール送信には TLS を必須とする」と宣言する仕組みです。送信側 MTA は _mta-sts.example.com の TXT レコードを確認し、https://mta-sts.example.com/.well-known/mta-sts.txt からポリシーを取得します。ポリシーのモードが enforce であれば、TLS 接続に失敗した場合はメール送信を保留します。MTA-STS は初回取得時に Trust On First Use(TOFU)に依存するため、最初のポリシー取得が改ざんされるリスクがあります。ただし、一度ポリシーをキャッシュすれば max_age の期間中はダウングレードを防止できます。
DANE(RFC 7672)は、DNSSEC で署名された TLSA レコードにサーバー証明書の情報を格納する方式です。送信側 MTA は DNS クエリで証明書を検証するため、TOFU の弱点がありません。
_25._tcp.mail.example.com. IN TLSA 3 1 1 abc123...
DANE は DNSSEC の導入が前提です。DNSSEC を利用しているドメインは全体の約 5% にとどまるため、普及は限定的です。
TLS-RPT(RFC 8460)は、TLS 接続の成功・失敗を送信側から受信側に報告する仕組みです。日和見 TLS で暗号化に失敗していることを検知するために使います。
_smtp._tls.example.com. IN TXT "v=TLSRPTv1; rua=mailto:tlsrpt@example.com"
送信側 MTA が TLS ネゴシエーションの結果を JSON レポートとして送信するため、ストリッピング攻撃やサーバー設定の問題を発見できます。
設定例
Postfix の日和見 TLS 設定と、MTA-STS を使った厳密な TLS への段階移行手順を示します。
Postfix での日和見 TLS
送信側(クライアント側)の設定です。
smtp_tls_security_level = may
smtp_tls_loglevel = 1
smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
may は日和見 TLS を有効にします。smtp_tls_loglevel = 1 は TLS のネゴシエーション結果をログに記録します。
受信側(サーバー側)の設定です。
smtpd_tls_cert_file = /etc/letsencrypt/live/mail.example.com/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/mail.example.com/privkey.pem
smtpd_tls_security_level = may
受信側の may は、STARTTLS を提供するがクライアントに強制しないことを意味します。
MTA-STS ポリシーで日和見 TLS から厳密な TLS へ移行
MTA-STS の導入手順です。
# ステップ 1: testing モードで開始
# https://mta-sts.example.com/.well-known/mta-sts.txt
version: STSv1
mode: testing
mx: mail.example.com
max_age: 86400
# ステップ 2: DNS に TXT レコードを追加
_mta-sts.example.com. IN TXT "v=STSv1; id=20260411T000000"
mode: testing の間は TLS-RPT レポートを監視し、問題がないことを確認してから mode: enforce に変更します。
確認方法
メールサーバーが STARTTLS に対応しているかを確認するには openssl s_client を使います。
openssl s_client -starttls smtp -connect mail.example.com:25 -servername mail.example.com
接続が成功すると、TLS バージョンと暗号スイートが表示されます。SSL-Session セクションの Protocol が TLSv1.2 や TLSv1.3 であれば STARTTLS が動作しています。
MTA-STS ポリシーの公開状況を確認するには、DNS の TXT レコードと HTTPS のポリシーファイルを確認します。
dig TXT _mta-sts.example.com +short
curl "https://mta-sts.example.com/.well-known/mta-sts.txt"
TLS-RPT レコードの設定を確認するには次のコマンドを使います。
dig TXT _smtp._tls.example.com +short
外部の視点からメール認証レコードの公開状況を確認したい場合は、Labee Dev Toolbox の Mail Auth API を使うと、外部の視点から見た結果を取得できます。
curl "https://labee.dev/api/mail-auth?domain=example.com"
{
"success": true,
"data": {
"spf": {
"record": "v=spf1 include:_spf.google.com ~all",
"exists": true
},
"dkim": {
"record": null,
"exists": false,
"selector": "default"
},
"dmarc": {
"record": "v=DMARC1; p=reject; rua=mailto:dmarc@example.com",
"exists": true
},
"bimi": {
"record": null,
"exists": false
}
},
"error": null,
"meta": { "responseTime": 120 }
}
Mail Auth API はメール認証レコード(SPF、DKIM、DMARC、BIMI)の公開状況を確認できます。日和見 TLS はトランスポート層の暗号化であり、SPF・DKIM・DMARC の送信ドメイン認証とは独立した仕組みです。トランスポート暗号化と送信ドメイン認証の両方を導入することで、メールのセキュリティを多層的に強化できます。
よくある問題
日和見 TLS は暗号化の失敗を隠蔽する設計のため、攻撃や設定不備の検知が困難です。
ストリッピング攻撃に気付かない
日和見 TLS は暗号化に失敗してもエラーを出さずに平文で送信を続行します。ストリッピング攻撃を受けても、送信側・受信側ともに正常に通信できてしまうため、攻撃の発生を検知できません。TLS-RPT を設定して TLS ネゴシエーションの失敗レポートを受け取ることで、異常を検知できます。
証明書検証をスキップしている
日和見 TLS の多くの実装は、証明書の有効性を検証しません。Postfix の smtp_tls_security_level = may では、自己署名証明書でも期限切れ証明書でも TLS 接続を受け入れます。暗号化自体は成立しますが、接続先が正当なサーバーであることは保証されません。中間者攻撃で攻撃者が自己署名証明書を提示しても、日和見 TLS はそれを受け入れます。MTA-STS の enforce モードでは CA が発行した有効な証明書が必要になるため、この問題を解消できます。
TLS バージョンの不一致
送信側と受信側でサポートする TLS バージョンが一致しない場合、TLS ハンドシェイクが失敗し、日和見 TLS は平文にフォールバックします。TLS 1.0 や TLS 1.1 を無効化したサーバーに対して、古い MTA がこれらのバージョンでのみ接続を試みるケースが該当します。Postfix では smtp_tls_protocols で対応するバージョンを指定できます。
MTA-STS の testing モードから移行しない
mode: testing は MTA-STS のポリシー違反を検知してもメール送信をブロックしません。TLS-RPT レポートで問題がないことを確認したら mode: enforce に変更します。testing のまま放置すると、ダウングレード攻撃への対策が実質的に機能しません。