[インデックス 18568] ファイルの概要
このコミットは、Go言語の標準ライブラリ crypto/tls
パッケージにおけるドキュメンテーションの改善に関するものです。特に、TLSクライアント接続を確立する際に使用される Config
構造体の ServerName
フィールドと、Client
関数に関する説明が更新されています。この変更の目的は、ユーザーがTLS証明書の検証メカニズムをより正確に理解し、安全な接続を確立できるようにすることにあります。
コミット
commit 80692a3f81f6367e9c61b652bf3dff30f4cc6624
Author: Adam Langley <agl@golang.org>
Date: Wed Feb 19 11:17:09 2014 -0500
crypto/tls: improve documentation for ServerName.
Users of the low-level, Client function are frequenctly missing the
fact that, unless they pass a ServerName to the TLS connection then it
cannot verify the certificates against any name.
This change makes it clear that at least one of InsecureSkipVerify and
ServerName should always be set.
LGTM=bradfitz
R=golang-codereviews, bradfitz
CC=golang-codereviews
https://golang.org/cl/65440043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/80692a3f81f6367e9c61b652bf3dff30f4cc6624
元コミット内容
このコミットは、crypto/tls
パッケージのドキュメンテーションを改善し、特に ServerName
フィールドの重要性を強調することを目的としています。Client
関数を使用する際に、ServerName
が設定されていないと証明書の検証が適切に行われないという問題が頻繁に発生していたため、InsecureSkipVerify
と ServerName
のいずれか一方が常に設定されるべきであることを明確にする変更が加えられました。
変更の背景
Go言語の crypto/tls
パッケージは、TLS (Transport Layer Security) プロトコルを実装し、セキュアな通信チャネルを提供します。TLSクライアントがサーバーに接続する際、サーバーから提示された証明書を検証することで、通信相手が正当なサーバーであることを確認します。この検証プロセスにおいて、サーバー証明書に記載されたホスト名と、クライアントが接続しようとしているホスト名が一致するかどうかのチェックが重要になります。
しかし、crypto/tls
パッケージの低レベルな Client
関数を使用する開発者の中には、Config
構造体の ServerName
フィールドの重要性を見落としがちなケースがありました。ServerName
フィールドは、TLSハンドシェイク中にServer Name Indication (SNI) 拡張としてサーバーに送信され、仮想ホスティング環境で複数のドメインが同じIPアドレスを共有している場合に、どの証明書を提示すべきかをサーバーに伝える役割を果たします。さらに重要なのは、GoのTLS実装において、この ServerName
がサーバー証明書のホスト名検証にも使用される点です。
ServerName
が設定されていない場合、GoのTLSクライアントは、提示されたサーバー証明書がどのホスト名に対して発行されたものかを判断できず、結果としてホスト名検証をスキップしてしまう可能性がありました。これは、中間者攻撃 (Man-in-the-Middle attack) のリスクを高め、セキュリティ上の脆弱性につながります。
このコミットは、このような誤用を防ぎ、開発者がより安全なTLS接続を構築できるように、既存のドキュメンテーションをより明確にすることを目的としています。特に、InsecureSkipVerify
(証明書検証を完全にスキップする設定) を使用しない限り、ServerName
を必ず設定する必要があるという点を強調しています。
前提知識の解説
TLS (Transport Layer Security)
TLSは、インターネット上で安全な通信を行うための暗号化プロトコルです。主に以下の機能を提供します。
- 認証: 通信相手が正当なサーバー(またはクライアント)であることを確認します。サーバー認証にはX.509デジタル証明書が使用されます。
- 機密性: 通信内容が第三者に盗聴されないように暗号化します。
- 完全性: 通信内容が途中で改ざんされていないことを保証します。
TLSハンドシェイクは、クライアントとサーバー間で暗号化パラメータをネゴシエートし、セキュアな通信チャネルを確立するプロセスです。
デジタル証明書とホスト名検証
デジタル証明書は、公開鍵と、その公開鍵が特定のエンティティ(例: ウェブサイトのドメイン名)に属することを証明する情報を含んでいます。認証局 (CA) によって署名され、その正当性が保証されます。
TLSクライアントは、サーバーから提示された証明書を検証する際に、以下の点をチェックします。
- 証明書が信頼できる認証局によって発行されているか。
- 証明書の有効期限が切れていないか。
- 証明書に記載されているホスト名(Common NameまたはSubject Alternative Name)が、クライアントが接続しようとしているホスト名と一致するか。
この3番目のチェックが「ホスト名検証」であり、TLS接続のセキュリティにおいて非常に重要です。
Server Name Indication (SNI)
SNIはTLSプロトコルの拡張機能で、クライアントがTLSハンドシェイクの初期段階で接続しようとしているホスト名をサーバーに伝えることを可能にします。これにより、一つのIPアドレスで複数のドメインをホストしているサーバーが、クライアントが要求しているドメインに対応する適切な証明書を提示できるようになります。SNIがない場合、サーバーはどの証明書を提示すべきか判断できず、デフォルトの証明書を提示するか、接続を拒否する可能性があります。
crypto/tls
パッケージ
Go言語の crypto/tls
パッケージは、TLSプロトコルをGoアプリケーションに統合するための機能を提供します。このパッケージには、TLSクライアントおよびサーバーの機能、証明書の管理、暗号スイートの選択など、TLS通信に必要な多くのコンポーネメントが含まれています。
tls.Config
構造体: TLS接続の設定をカプセル化する構造体です。証明書、鍵、ルートCA、サポートするプロトコルバージョン、暗号スイート、そしてこのコミットで焦点となっているServerName
やInsecureSkipVerify
などの設定が含まれます。Config.ServerName
フィールド: クライアントが接続しようとしているサーバーのホスト名を指定します。この値はSNIとして送信され、サーバー証明書のホスト名検証にも使用されます。Config.InsecureSkipVerify
フィールド: このブール値がtrue
に設定されている場合、クライアントはサーバー証明書の検証を完全にスキップします。これは、自己署名証明書を使用するテスト環境など、特定の状況でのみ使用されるべきであり、本番環境での使用はセキュリティリスクを伴うため強く推奨されません。tls.Client(conn net.Conn, config *Config) *Conn
関数: 指定されたネットワーク接続 (net.Conn
) とTLS設定 (*tls.Config
) を使用して、新しいTLSクライアント接続を確立します。
技術的詳細
このコミットは、既存のGo言語の crypto/tls
パッケージ内のドキュメンテーションコメントを修正することで、TLSクライアント接続のセキュリティを向上させることを目的としています。具体的には、tls.Config
構造体の ServerName
フィールドと、tls.Client
関数のドキュメンテーションが変更されました。
変更の核心は、ServerName
フィールドが単に仮想ホスティングをサポートするためだけでなく、サーバー証明書のホスト名検証にも使用されるという点を明確にすることです。また、InsecureSkipVerify
が true
でない限り、この検証が実行されることを強調しています。
さらに、tls.Client
関数のドキュメンテーションでは、config
引数が nil
であってはならず、ユーザーは ServerName
または InsecureSkipVerify
のいずれかを必ず設定する必要があるという、より厳格な要件が追加されました。これにより、開発者が意図せず証明書検証をスキップしてしまう状況を防ぎ、より安全なTLS接続の確立を促します。
これらのドキュメンテーションの改善は、コードの動作自体を変更するものではありませんが、開発者が crypto/tls
パッケージをより安全かつ効果的に使用するための重要なガイダンスを提供します。特に、TLSのセキュリティモデルにおいてホスト名検証がいかに重要であるかを再認識させ、一般的な誤用パターンを回避するための明確な指示を与えます。
コアとなるコードの変更箇所
このコミットでは、以下の2つのファイルが変更されています。
src/pkg/crypto/tls/common.go
src/pkg/crypto/tls/tls.go
src/pkg/crypto/tls/common.go
の変更
Config
構造体の ServerName
フィールドのコメントが変更されました。
--- a/src/pkg/crypto/tls/common.go
+++ b/src/pkg/crypto/tls/common.go
@@ -231,8 +231,9 @@ type Config struct {
// NextProtos is a list of supported, application level protocols.
NextProtos []string
- // ServerName is included in the client's handshake to support virtual
- // hosting.
+ // ServerName is used to verify the hostname on the returned
+ // certificates unless InsecureSkipVerify is given. It is also included
+ // in the client's handshake to support virtual hosting.
ServerName string
// ClientAuth determines the server's policy for
src/pkg/crypto/tls/tls.go
の変更
Client
関数のコメントが変更されました。
--- a/src/pkg/crypto/tls/tls.go
+++ b/src/pkg/crypto/tls/tls.go
@@ -27,9 +27,8 @@ func Server(conn net.Conn, config *Config) *Conn {
// Client returns a new TLS client side connection
// using conn as the underlying transport.
-// Client interprets a nil configuration as equivalent to
-// the zero configuration; see the documentation of Config
-// for the defaults.
+// The config cannot be nil: users must set either ServerHostname or
+// InsecureSkipVerify in the config.
func Client(conn net.Conn, config *Config) *Conn {
return &Conn{conn: conn, config: config, isClient: true}
}
コアとなるコードの解説
src/pkg/crypto/tls/common.go
の変更解説
Config
構造体の ServerName
フィールドのドキュメンテーションは、その役割をより正確に反映するように更新されました。
変更前:
ServerName
は「クライアントのハンドシェイクに含まれ、仮想ホスティングをサポートする」とだけ説明されていました。これはSNIの機能としては正しいですが、GoのTLS実装における ServerName
のもう一つの重要な役割、すなわち証明書のホスト名検証については触れられていませんでした。
変更後:
「ServerName
は、InsecureSkipVerify
が与えられない限り、返された証明書のホスト名を検証するために使用されます。また、仮想ホスティングをサポートするためにクライアントのハンドシェイクにも含まれます。」という説明が追加されました。
この変更により、開発者は ServerName
が単なるSNIのためだけでなく、セキュリティ上重要な証明書検証の基準としても機能することを明確に理解できるようになります。これにより、ServerName
を設定しないことが、意図しない証明書検証のスキップにつながる可能性があるという認識が高まります。
src/pkg/crypto/tls/tls.go
の変更解説
Client
関数のドキュメンテーションは、config
引数の取り扱いに関する重要な制約を明確にするために変更されました。
変更前:
Client
関数は、「nil
の設定をゼロ設定と同等に解釈する」と説明されており、Config
のデフォルトについては別途ドキュメンテーションを参照するよう促していました。これは、nil
Config
が許容されるという誤解を招く可能性がありました。
変更後:
「config
は nil
にできません。ユーザーは config
内で ServerHostname
(これは ServerName
の誤記または古い名称) または InsecureSkipVerify
のいずれかを設定する必要があります。」という、より厳格で具体的な指示に置き換えられました。
この変更は、Client
関数を呼び出す際に Config
オブジェクトが必須であり、さらにその Config
オブジェクト内で ServerName
(ホスト名検証のため) または InsecureSkipVerify
(検証を意図的にスキップするため) のいずれかが明示的に設定されている必要があることを強調しています。これにより、開発者がTLS接続のセキュリティ設定を意識的に行うよう促し、デフォルトで安全でない状態になることを防ぎます。
関連リンク
- Go言語
crypto/tls
パッケージのドキュメンテーション: https://pkg.go.dev/crypto/tls - Server Name Indication (SNI) の詳細: https://en.wikipedia.org/wiki/Server_Name_Indication
参考にした情報源リンク
- Go言語の公式ドキュメンテーション
- TLSプロトコルに関する一般的な情報源 (例: Wikipedia)
- コミットメッセージと差分 (diff)
- Go言語のコードレビューシステム (Gerrit) の関連リンク:
https://golang.org/cl/65440043
(現在はhttps://go.dev/cl/65440043
にリダイレクトされる可能性があります)