ちょっと話題の記事

知られたくないドメインのSSL/TLS証明書を取得する場合は証明書の透明性(CT)を無効にしよう(AWS Certificate Manager編)

2021.12.19

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

SSL/TLS証明書(以下証明書)には証明書の監視や監査を行って証明書の信頼性を高める「Certificate Transparency(証明書の透明性;以下CT)」という仕組みがあります。

Certificate Transparency : Certificate Transparency

CAが証明書を発行する際には、パブリックなCTログサーバーに発行履歴を登録し、ログサーバーから受け取った署名付きのタイムスタンプ(SCT;Signed Certificate Timestamp)を埋め込んだ証明書を発行します(埋め込まない方法も有り)。

ブラウザは証明書に埋め込まれたSCTを確認し、存在しなければ証明書を不正とみなします(ブラウザによります)。

また、CAやドメイン管理者にとっては、CTログサーバーを監視することで、不正に発行された証明書を早期に検知できます。

※図は https://certificate.transparency.dev/howctworks/ から

試しに dev.classmethod.jp の証明書の SCT を確認してみましょう。

Embedded Signed Certificate Timestamp List の Log Operator から

  • Google
  • DigiCert
  • Cloudflare

の SCT が含まれていることがわかります。

このフレームワークは rfc6962 : Certificate Transparency で標準化されています。

CT はその透明性ゆえ、証明書発行の不正利用の早期検知に役に立つ一方で、公にしたくないドメインを公開してしまう問題もはらんでいます。

本記事では、AWS Certificate Manager(ACM)で証明書を取得する時に、CTを無効化する方法をご紹介します。

CT のメリット

ドメインの所有者やCAの場合、CTログから不正な証明書が発行されていないか監視する事ができます。

例えば、Cloudflare には CT Monitoring というサービスが存在し、CTログで保有ドメインに対する証明書発行のログを検知すると、通知することができます。

また、サイトにアクセスする一般利用者の場合、SCTの存在しない証明書を怪しいと判断することができます。

CT のデメリット

一方で、CT にはデメリットもあります。

CTはその透明性(transparency)の仕組みから、発行された証明書がパブリックな CT ログサーバーに登録されます。

例えば、新規サービス向けにサブドメインを割り当て、その証明書を取得すると、そのサブドメインが漏洩してしまいます。

CT ログオペレーターの Google は、証明書をホスト名で検索するサービスも提供しています。

試しに example.com の証明書をサブドメインも含めて検索してみましょう

www.example.com など、サブドメイン含め、取得された証明書を簡単に閲覧できます。

Chrome(Edge含む)などのブラウザは SCT ログのない証明書を不正とみなすため、主要CAはCTログをデフォルトで登録します。

以下では、ACM(AWS Certificate Manager)で証明書を取得する際に、ホスト名がCTログサーバーに登録されないよう、CTを無効化する方法を紹介します。

ACM(AWS Certificate Manager)でCTログをオプトアウトするには?

AWSの証明書を発行するサービス ACM は CTログをオプトアウトさせることができます。

ACM のベストプラクティスドキュメントに、CT(証明書の透明性)ログの潜在リスクとオプトアウトする方法が記載されています。

証明書の透明性ログ記録のオプトアウト

...(中略) ログ記録は、証明書をリクエストするとき、または証明書が更新されたときに自動的に実行されますが、オプトアウトすることもできます。その一般的な理由には、セキュリティとプライバシーに関する懸念があります。たとえば、内部ホストドメイン名のログ記録により、それ以外の場合には公開されない内部ネットワークについての情報が潜在的な攻撃者に提供されます。さらに、ログ記録により、新規または未リリース製品やウェブサイトの名前が漏洩する可能性があります。

証明書をリクエストするときに、透明性ログを出力しないようにするには、request-certificate AWS CLIコマンド、または RequestCertificateAPI オペレーションの options パラメータを使用します。証明書が 2018 年 4 月 24 日より前に発行され、更新中にログに記録されないようにする場合は、 コマンド、または UpdateCertificateOptions API オペレーションを使用してオプトアウトすることができます。

ACM でCTログをオプトアウトしてみる

CTログのオプトアウトはコンソールからは選択できないため、AWS CLIまたは SDK で acm request-certificate API を呼び出します。

ポイントは オプションで CertificateTransparencyLoggingPreference=DISABLED を渡すことです。

$ aws acm request-certificate \
  --domain-name sct.example.com \
  --validation-method DNS \
  --options CertificateTransparencyLoggingPreference=DISABLED
{
    "CertificateArn": "arn:aws:acm:us-east-1:123:certificate/xxx-xxx-xxx-xxx-xxx"
}

CTを無効にした証明書をサーバーに適用し、Chrome からアクセスしてみましょう。

ChromeはSCTが存在しない証明書を不正とみなすため、NET::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED エラーが発生しました。

CT を考案したGoogle 謹製の SCT チェックツールでコマンドラインからも SCT を検証してみましょう。

$ go install github.com/google/certificate-transparency-go/ctutil/sctcheck@latest

$ sctcheck --logtostderr https://sct.example.co/
I1218 13:10:28.036546    1178 sctcheck.go:164] Retrieve certificate chain from TLS connection to "sct.example.co:443"
I1218 13:10:28.063165    1178 sctcheck.go:177] Found chain of length 4
E1218 13:10:28.064150    1178 sctcheck.go:78] Found 0 external SCTs for "https://sct.example.co/", of which 0 were validated
E1218 13:10:28.064164    1178 sctcheck.go:99] Found 0 embedded SCTs for "https://sct.example.co/", of which 0 were validated

証明書に対応する SCT が存在しないことがわかります。

比較のために、SCT を含んだ証明書への実行ログも共有します。

$ sctcheck --logtostderr https://dev.classmethod.jp
I1218 08:35:34.272440    3509 sctcheck.go:164] Retrieve certificate chain from TLS connection to "dev.classmethod.jp:443"
I1218 08:35:34.940379    3509 sctcheck.go:177] Found chain of length 4
E1218 08:35:34.940993    3509 sctcheck.go:78] Found 0 external SCTs for "https://dev.classmethod.jp", of which 0 were validated
I1218 08:35:34.941130    3509 sctcheck.go:222] Examine embedded SCT[0] with timestamp: 1620519588587 (2021-05-09 00:19:48.587 +0000 UTC) from logID: 2979bef09e393921f056739f63a577e5be577d9c600af8f94d5d265c255dc7
84
I1218 08:35:34.941272    3509 sctcheck.go:235] Validate embedded SCT[0] against log "Google 'Argon2022' log"...
I1218 08:35:34.941449    3509 sctcheck.go:240] Validate embedded SCT[0] against log "Google 'Argon2022' log"... validated
I1218 08:35:34.941465    3509 sctcheck.go:244] Check embedded SCT[0] inclusion against log "Google 'Argon2022' log"...
I1218 08:35:35.304628    3509 sctcheck.go:255] Check embedded SCT[0] inclusion against log "Google 'Argon2022' log"... included at 41353849
I1218 08:35:35.304740    3509 sctcheck.go:222] Examine embedded SCT[1] with timestamp: 1620519587561 (2021-05-09 00:19:47.561 +0000 UTC) from logID: 2245450759552456963fa12ff1f76d86e0232663adc04b7f5dc6835c6ee20f
02
I1218 08:35:35.304875    3509 sctcheck.go:235] Validate embedded SCT[1] against log "DigiCert Yeti2022 Log"...
I1218 08:35:35.305039    3509 sctcheck.go:240] Validate embedded SCT[1] against log "DigiCert Yeti2022 Log"... validated
I1218 08:35:35.305072    3509 sctcheck.go:244] Check embedded SCT[1] inclusion against log "DigiCert Yeti2022 Log"...
I1218 08:35:36.053546    3509 sctcheck.go:255] Check embedded SCT[1] inclusion against log "DigiCert Yeti2022 Log"... included at 42240070
I1218 08:35:36.053736    3509 sctcheck.go:222] Examine embedded SCT[2] with timestamp: 1620519588564 (2021-05-09 00:19:48.564 +0000 UTC) from logID: 41c8cab1df22464a10c6a13a0942875e4e318b1b03ebeb4bc768f090629606
f6
I1218 08:35:36.053823    3509 sctcheck.go:235] Validate embedded SCT[2] against log "Cloudflare 'Nimbus2022' Log"...
I1218 08:35:36.053985    3509 sctcheck.go:240] Validate embedded SCT[2] against log "Cloudflare 'Nimbus2022' Log"... validatedI1218 08:35:36.054008    3509 sctcheck.go:244] Check embedded SCT[2] inclusion against log "Cloudflare 'Nimbus2022' Log"...
I1218 08:35:36.612876    3509 sctcheck.go:255] Check embedded SCT[2] inclusion against log "Cloudflare 'Nimbus2022' Log"... included at 40019104
E1218 08:35:36.612911    3509 sctcheck.go:99] Found 3 embedded SCTs for "https://dev.classmethod.jp", of which 3 were validated
  • Google Argon
  • DigiCert Yeti
  • Cloudflare Nimbus

へのログ登録を確認できます。

CTを無効にする場合、SCT検証をしないブラウザを推奨したり、Chrome/Edge のようにSCT検証をするブラウザにも対応するのであれば、次のURLのように対象ドメインに対して CertificateTransparencyEnforcementDisabledForUrls ポリシーでCTチェックを無効化できます。

Chrome Enterprise Policy List & Management | Documentation

既存の ACM 証明書の CT ログオプションを変更

acm::update-certificate-options API を利用すると、CTログオプションを変更できます。

試しに、オプトイン(有効化)します。

$ aws acm update-certificate-options \
  --certificate-arn arn:aws:acm:us-east-1:123:certificate/xxx-yyy-zzz-aaa \
  --options CertificateTransparencyLoggingPreference=ENABLED
$

ただし、この操作には問題があります。

CTログを無効化しても、過去の登録済みのCTログを削除することはできません。

また、CTログを有効化しても、CTログが登録されるのは、証明書を更新(=発行)するタイミングです。 SCTを埋め込んだ証明書が即座に必要な場合、CTログを有効にした証明書を新規に取得してください。

最後に

TLS/SSL証明書には、証明書の発行状況を監視・監査する証明書の透明性(Certificate Transparency/CT)という仕組みがあります。

CTを活用することで、意図せず発行された証明書を早期に検知できることが期待されます。 一方で、CTの透明性故、公開したくないドメイン情報が漏洩してしまうリスクもあります。

漏洩を避けたい場合は、ワイルドカード証明書を発行したり、CTログを無効にした証明書を発行してください。

後者の場合、ドメインがパブリックにならない一方で、Chrome のように証明書のSCTを検証するブラウザからはアクセスできなくなります。

SCT検証しないブラウザを利用したり、Chromeに対して特定のドメインをCTチェックから除外するポリシーを追加してください。

それでは。

参考