Goブログ
crypto/tlsにおける自動暗号スイート順序付け
Go標準ライブラリは、インターネット上で最も重要なセキュリティプロトコルであり、HTTPSの基本コンポーネントであるトランスポート層セキュリティ(TLS)の堅牢な実装であるcrypto/tls
を提供します。Go 1.17では、暗号スイートの優先順位を自動化することにより、その設定をより簡単、より安全、より効率的にしました。
暗号スイートの仕組み
暗号スイートは、TLSの前身であるセキュアソケットレイヤ(SSL)にまでさかのぼり、「暗号の種類」と呼ばれていました。これらは、TLS_RSA_WITH_AES_256_CBC_SHA
やTLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
のような、一見複雑に見える識別子で、TLS接続におけるキーの交換、証明書の認証、レコードの暗号化に使用されるアルゴリズムを指定します。
暗号スイートはTLSハンドシェイク中にネゴシエートされます。クライアントは最初のメッセージであるクライアントヘッロでサポートする暗号スイートのリストを送信し、サーバーはそのリストから1つを選択して、その選択をクライアントに伝えます。クライアントは、独自の優先順位でサポートされている暗号スイートのリストを送信し、サーバーは自由に選択できます。通常、サーバーは、クライアントの優先順位またはサーバーの優先順位のいずれかで、相互にサポートされている最初の暗号スイートを選択します。これはサーバーの設定に基づきます。
暗号スイートは、ネゴシエートされる多数のパラメータの1つにすぎません(サポートされるカーブ/グループと署名アルゴリズムは、独自の拡張機能を通じて追加でネゴシエートされます)。しかし、最も複雑で有名なものであり、長年にわたって開発者や管理者が意見を持ってきた唯一のものです。
TLS 1.0~1.2では、これらのパラメータは複雑な相互依存関係の網状構造で相互作用します。たとえば、サポートされる証明書は、サポートされる署名アルゴリズム、サポートされるカーブ、サポートされる暗号スイートに依存します。TLS 1.3では、これは大幅に簡素化されました。暗号スイートは対称暗号化アルゴリズムのみを指定し、サポートされるカーブ/グループはキー交換を管理し、サポートされる署名アルゴリズムは証明書に適用されます。
開発者に委ねられた複雑な選択
ほとんどのHTTPSおよびTLSサーバーは、暗号スイートと優先順位の選択をサーバーオペレーターまたはアプリケーション開発者に委任しています。これは、多くの理由から最新かつ専門的な知識が必要な複雑な選択です。
古い暗号スイートの中には、安全でないコンポーネントを持つもの、安全に実装するには非常に注意深く複雑な実装が必要なもの、クライアントが特定の軽減策を適用する場合、または特定のハードウェアを持つ場合にのみ安全なものがあります。個々のコンポーネントのセキュリティを超えて、異なる暗号スイートは接続全体に大きく異なるセキュリティ特性を提供できます。ECDHEまたはDHEを使用しない暗号スイートは、フォワードシークレシー(証明書のキーを使用して接続を遡及的または受動的に復号化できないという特性)を提供しません。最後に、サポートされる暗号スイートの選択は、互換性とパフォーマンスに影響を与え、エコシステムを最新の状態に理解せずに変更を加えると、レガシークライアントからの接続が切断されたり、サーバーで消費されるリソースが増加したり、モバイルクライアントのバッテリが消耗したりする可能性があります。
この選択は非常に難解で繊細なため、優れたMozilla SSL Configuration Generatorなど、オペレーターを支援する専用のツールがあります。
なぜこのような状況になったのか
まず、個々の暗号化コンポーネントは以前ははるかに頻繁に破られました。2011年、BEAST攻撃がCBC暗号スイートをクライアントのみが攻撃を軽減できるような方法で破ったとき、サーバーは影響を受けないRC4を優先するようになりました。2013年、RC4が破損していることが明らかになると、サーバーはCBCに戻りました。Lucky Thirteenにより、その逆方向のMAC-then-encrypt設計によりCBC暗号スイートを実装することが非常に困難であることが明らかになると…、他に選択肢がなかったので、実装は慎重に困難な作業をこなす必要があり、長年にわたってその困難なタスクに失敗し続けました。構成可能な暗号スイートと暗号の俊敏性は、コンポーネントが破損した場合にその場で置き換えられるという安心感を与えていました。
最新の暗号化は大きく異なります。プロトコルは時々破られる可能性がありますが、失敗するのはめったに抽象化された個々のコンポーネントではありません。2008年にTLS 1.2で導入されたAEADベースの暗号スイートは、どれも破られていません。今日では、暗号の俊敏性は責任です。これは、弱点やダウングレードにつながる複雑さを導入し、パフォーマンスとコンプライアンスの理由でのみ必要です。
パッチの適用方法も以前とは異なっていました。今日では、公開された脆弱性に対するソフトウェアパッチを迅速に適用することが安全なソフトウェア展開の基盤であることを認識していますが、10年前は標準的な慣習ではありませんでした。構成の変更は、脆弱な暗号スイートに対応するためのより迅速なオプションと見なされていたため、オペレーターは構成を通じて完全に担当していました。現在、私たちは反対の問題を抱えています。構成が長年変更されていないため、依然として奇妙に、最適ではない、または安全ではない動作をする、完全にパッチが適用され更新されたサーバーがあります。
最後に、サーバーはクライアントよりも更新が遅れる傾向があり、そのため、最適な暗号スイートの選択の判断が信頼できないことが理解されていました。ただし、サーバーは暗号スイートの選択に関して最終決定権を持っているため、デフォルトでは、強い意見を持つ代わりに、サーバーがクライアントの優先順位に従うようになりました。これは今でも部分的に当てはまります。ブラウザは自動更新を実現し、平均的なサーバーよりもはるかに最新の状態にあります。一方、多くのレガシーデバイスは現在サポートされておらず、古いTLSクライアント構成に固定されているため、最新のサーバーの方がクライアントよりも優れた選択を行うことができます。
どのような経緯でここまで至ったかに関係なく、アプリケーション開発者やサーバーオペレーターに暗号スイート選択のニュアンスに関する専門知識を持たせ、構成を最新の状態に保つために最新の開発状況を把握させることは、暗号化エンジニアリングの失敗です。彼らが私たちのセキュリティパッチを展開しているのであれば、それだけで十分です。
Mozilla SSL Configuration Generatorは優れていますが、存在するべきではありません。
状況は改善していますか?
過去数年間の傾向には、良いニュースと悪いニュースがあります。悪いニュースは、同等のセキュリティ特性を持つ暗号スイートのセットがあるため、順序付けがさらに微妙になっていることです。そのようなセット内の最適な選択は、利用可能なハードウェアに依存し、構成ファイルで表現するのは困難です。他のシステムでは、単純な暗号スイートのリストとして始まったものが、より複雑な構文やSSL_OP_PRIORITIZE_CHACHAなどの追加フラグに依存するようになりました。
良いニュースは、TLS 1.3が暗号スイートを大幅に簡素化し、TLS 1.0~1.2とは異なるセットを使用していることです。すべてのTLS 1.3暗号スイートは安全であるため、アプリケーション開発者やサーバーオペレーターはそれについてまったく心配する必要はありません。実際、BoringSSLやGoのcrypto/tls
などの一部のTLSライブラリでは、それらをまったく構成できません。
Goのcrypto/tlsと暗号スイート
Goでは、TLS 1.0~1.2で暗号スイートを構成できます。アプリケーションは常に、Config.CipherSuites
を使用して、有効な暗号スイートと優先順位を設定できます。 Config.PreferServerCipherSuites
が設定されていない限り、サーバーはデフォルトでクライアントの優先順位を優先します。
Go 1.12でTLS 1.3を実装したとき、TLS 1.3暗号スイートを構成可能にしませんでした。これは、TLS 1.0~1.2のものとは異なるセットであり、最も重要なのはすべて安全であるため、アプリケーションに選択を委任する必要がないためです。Config.PreferServerCipherSuites
は、どちら側の優先順位が使用されるかを依然として制御し、ローカル側の優先順位は利用可能なハードウェアによって異なります。
Go 1.14では、サポートされている暗号スイートを公開しましたが、優先順位ロジックを静的なソート順序で表現することにならないように、中立的な順序(IDでソート)で明示的に返すように選択しました。
Go 1.16では、クライアントまたはサーバーのいずれかにAES-GCMのハードウェアサポートがないことを検出した場合に、サーバーでChaCha20Poly1305暗号スイートをAES-GCMよりも優先的に使用し始めました。これは、AES-GCMは専用のハードウェアサポート(AES-NIやCLMUL命令セットなど)がないと、効率的かつ安全に実装することが困難であるためです。
最近リリースされたGo 1.17では、すべてのGoユーザーに対して暗号スイートの優先順位の順序付けを引き継ぎました。Config.CipherSuites
は依然として、有効にするTLS 1.0~1.2暗号スイートを制御しますが、順序付けには使用されず、Config.PreferServerCipherSuites
は無視されます。代わりに、crypto/tls
は利用可能な暗号スイート、ローカルハードウェア、および推測されたリモートハードウェア機能に基づいて、すべての順序付けの決定を行います。
現在のTLS 1.0~1.2順序付けロジックは、次のルールに従います。
-
ECDHEは、静的なRSAキー交換よりも優先されます。
暗号スイートの最も重要な特性は、フォワードシークレシーを実現することです。「古典的」な有限体Diffie-Hellmanは、複雑で、遅く、弱く、TLS 1.0~1.2では微妙に破られているため実装しません。そのため、レガシーな静的RSA鍵交換よりも楕円曲線Diffie-Hellman鍵交換を優先します。(後者は、接続の秘密を証明書の公開鍵で暗号化するだけで、将来証明書が侵害された場合に復号化できるようになります。)
-
暗号化には、CBCよりもAEADモードが優先されます。
Lucky13に対する部分的な対策を実装した場合でも(2015年にGo標準ライブラリへの私の最初の貢献です!)、CBCスイートは正しく実装するのが非常に困難であるため、他の重要な要素が同等である限り、代わりにAES-GCMとChaCha20Poly1305を選択します。
-
3DES、CBC-SHA256、RC4は、他に何も利用できない場合にのみ、この優先順位で利用されます。
3DESは64ビットブロックを使用しているため、十分なトラフィックがあれば、誕生日攻撃に対して根本的に脆弱です。3DESは
InsecureCipherSuites
に記載されていますが、互換性のためにデフォルトで有効になっています。(優先順位を制御することの追加の利点は、より安全性の低い暗号スイートをデフォルトで有効にしておくことができ、アプリケーションやクライアントが最後の手段として選択しない限り、心配する必要がないことです。これは、より優れた代替手段をサポートするピアを攻撃するために、より弱い暗号スイートの可用性に依存するダウングレード攻撃がないため安全です。)CBC暗号スイートはLucky13スタイルのサイドチャネル攻撃に対して脆弱であり、SHA-1ハッシュについては上記で説明した複雑な対策を部分的に実装するだけで、SHA-256については実装していません。CBC-SHA1スイートは互換性があるため、追加の複雑さが正当化されますが、CBC-SHA256スイートはそうではないため、デフォルトで無効になっています。
RC4には事実上悪用可能なバイアスがあり、サイドチャネルなしで平文の復元につながる可能性があります。これ以上に悪くなることはありません。そのため、RC4はデフォルトで無効になっています。
-
両側が後者のハードウェアサポートを持っている場合を除き、暗号化にはChaCha20Poly1305がAES-GCMよりも優先されます。
上記で説明したように、AES-GCMはハードウェアサポートなしでは効率的かつ安全に実装することが困難です。ローカルのハードウェアサポートがないこと、または(サーバー上で)クライアントがAES-GCMを優先していないことを検出すると、代わりにChaCha20Poly1305を選択します。
-
暗号化には、AES-256よりもAES-128が優先されます。
AES-256はAES-128よりも大きな鍵を持っていますが、これは通常は良いことですが、コア暗号化関数のラウンド数も多くなり、速度が遅くなります。(AES-256の追加ラウンドは、鍵サイズの変更とは無関係です。暗号解読に対するより広い余裕を提供するための試みです。)より大きな鍵は、多ユーザー設定とポスト量子設定でのみ有用ですが、これはTLSには関係ありません。TLSは十分にランダムなIVを生成し、ポスト量子鍵交換のサポートがありません。より大きな鍵に利点がないため、速度を優先してAES-128を優先します。
TLS 1.3の順序付けロジックでは、最後の2つのルールのみが必要になります。TLS 1.3では、最初の3つのルールが保護している問題のあるアルゴリズムが削除されているためです。
よくある質問
暗号スイートが破られた場合はどうなりますか?他の脆弱性と同様に、サポートされているすべてのGoバージョンに対するセキュリティリリースで修正されます。安全に運用するには、すべてのアプリケーションでセキュリティ修正を適用する準備が必要です。歴史的に、破られた暗号スイートはますます少なくなっています。
TLS 1.0~1.2暗号スイートの設定可能を維持する理由は何ですか?有効にする暗号スイートを選択する際には、ベースラインセキュリティとレガシー互換性の間で意味のあるトレードオフを行う必要があり、エコシステムの受け入れられない部分を切り捨てるか、現代のユーザーのセキュリティ保証を低下させることなく、私たち自身でその選択を行うことはできません。
TLS 1.3暗号スイートを設定可能にしない理由は何ですか?逆に、TLS 1.3では、すべての暗号スイートが強力なセキュリティを提供するため、トレードオフを行う必要はありません。これにより、すべてを有効にしておき、開発者の関与を必要とせずに、接続の具体的な状況に基づいて最速のものを選択できます。
重要なポイント
Go 1.17以降、crypto/tls
は、使用可能な暗号スイートの選択順序を引き継いでいます。定期的に更新されたGoバージョンを使用することで、古いクライアントに順序を選択させるよりも安全になり、パフォーマンスを最適化でき、Go開発者の負担となる複雑さを軽減できます。
これは、可能な限り暗号化に関する決定を行い、開発者に委任しないという一般的な考え方と、暗号化原則と一致しています。他のTLSライブラリも同様の変更を採用し、繊細な暗号スイートの設定が過去のものになることを願っています。
次の記事:行動規範の更新
前の記事:Go Webエクスペリエンスの整理
ブログインデックス