Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 12089] ファイルの概要

このコミットは、Go言語の標準ライブラリであるnet/httpパッケージにおいて、http.Server構造体にTLSConfigという新しいフィールドを追加し、ListenAndServeTLS関数がより柔軟なTLS設定を受け入れられるようにする変更です。これにより、ユーザーはTLS接続の挙動を細かく制御できるようになります。

コミット

net/http: add optional Server.TLSConfig field

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5688047

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/dc19b94b21710a38858e32548cac74e0d406549d

元コミット内容

net/http: add optional Server.TLSConfig field

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5688047

変更の背景

Go言語のnet/httpパッケージは、ウェブサーバーを構築するための基本的な機能を提供します。以前のバージョンでは、http.Server構造体にはTLS(Transport Layer Security)接続に関する直接的な設定オプションがありませんでした。ListenAndServeTLS関数は、証明書ファイルと秘密鍵ファイルのパスを受け取り、内部でデフォルトのtls.Configを生成してTLSリスナーを設定していました。

しかし、このアプローチでは、ユーザーがTLS接続の挙動を細かく制御したい場合に限界がありました。例えば、特定のTLSバージョンを強制したり、カスタムの暗号スイートを指定したり、クライアント証明書認証を設定したりといった高度な要件に対応できませんでした。

このコミットの背景には、このような柔軟性の欠如を解消し、開発者がより詳細なTLS設定をhttp.Serverインスタンスに直接適用できるようにするという目的があります。これにより、net/httpパッケージを利用するアプリケーションが、セキュリティ要件やパフォーマンス要件に応じてTLS接続を最適化できるようになります。

前提知識の解説

net/httpパッケージ

Go言語の標準ライブラリで、HTTPクライアントとサーバーの実装を提供します。ウェブアプリケーションの構築において中心的な役割を果たします。

  • http.Server: HTTPサーバーの構成を定義する構造体です。アドレス、ハンドラー、タイムアウトなどの設定が含まれます。
  • ListenAndServeTLS(certFile, keyFile string) error: http.Serverのメソッドで、指定された証明書ファイルと秘密鍵ファイルを使用してHTTPSサーバーを起動します。

crypto/tlsパッケージ

Go言語の標準ライブラリで、TLS(Transport Layer Security)プロトコルを実装するための機能を提供します。セキュアなネットワーク通信を実現するために使用されます。

  • tls.Config: TLS接続の構成を定義する構造体です。この構造体には、証明書、秘密鍵、サポートするTLSバージョン、暗号スイート、クライアント認証設定など、TLS接続に関するあらゆる詳細な設定が含まれます。
    • Rand io.Reader: 乱数ジェネレータを指定するためのフィールドです。TLSハンドシェイクなどで使用される乱数を生成するために利用されます。通常はcrypto/rand.Readerが使用されます。
    • NextProtos []string: ALPN (Application-Layer Protocol Negotiation) でネゴシエートされるプロトコルリストを指定するためのフィールドです。HTTP/2などの上位プロトコルをネゴシエートするために使用されます。ウェブサーバーの場合、通常は"http/1.1"が含まれます。

TLS (Transport Layer Security)

インターネット上で安全な通信を行うための暗号化プロトコルです。データの盗聴、改ざん、なりすましを防ぎます。HTTPSはHTTP通信をTLSで暗号化したものです。

ALPN (Application-Layer Protocol Negotiation)

TLSハンドシェイク中に、クライアントとサーバーがどのアプリケーション層プロトコル(例: HTTP/1.1, HTTP/2)を使用するかをネゴシエートするためのTLS拡張です。

技術的詳細

このコミットの主要な変更点は、http.Server構造体にTLSConfig *tls.Configフィールドが追加されたことです。これにより、http.Serverのインスタンスを作成する際に、カスタムのtls.Configオブジェクトを直接設定できるようになりました。

以前のListenAndServeTLS関数は、内部で以下のようなデフォルトのtls.Configを生成していました。

config := &tls.Config{
    Rand:       rand.Reader,
    NextProtos: []string{"http/1.1"},
}

このコミットにより、ListenAndServeTLSの挙動が変更されました。

  1. http.Server.TLSConfigの利用: ListenAndServeTLSが呼び出された際、まずsrv.TLSConfignilでないかを確認します。もしnilでなければ、そのtls.Configオブジェクトのコピーを基にしてTLS設定を構築します。これにより、ユーザーがhttp.Serverに設定したカスタムのtls.Configが優先的に使用されるようになります。
  2. NextProtosのデフォルト設定: srv.TLSConfigが指定された場合でも、そのNextProtosフィールドがnilであれば、引き続き[]string{"http/1.1"}がデフォルトとして設定されます。これは、ALPNのネゴシエーションにおいてHTTP/1.1が常にサポートされるようにするためのフォールバックメカニズムです。
  3. crypto/randのインポート削除: tls.ConfigRandフィールドは、デフォルトでcrypto/rand.Readerが使用されるため、net/http/server.go内で明示的にcrypto/randをインポートする必要がなくなりました。これにより、依存関係が整理され、コードがよりクリーンになります。

この変更により、開発者はhttp.Serverインスタンスを介してTLS設定を完全に制御できるようになり、例えば以下のようなことが可能になります。

  • カスタム証明書と鍵のロード: tls.Config.Certificatesフィールドを使用して、ファイルパスではなくメモリ上の証明書と鍵を直接指定できます。
  • クライアント証明書認証: tls.Config.ClientAuthtls.Config.ClientCAsを設定することで、クライアントからの証明書を検証し、認証を行うことができます。
  • 特定のTLSバージョンと暗号スイートの強制: tls.Config.MinVersion, tls.Config.MaxVersion, tls.Config.CipherSuitesを設定することで、セキュリティ要件に応じて使用可能なTLSバージョンと暗号スイートを制限できます。
  • セッション再開の制御: tls.Config.SessionTicketsDisabledtls.Config.TicketKeysを設定することで、TLSセッション再開の挙動を制御できます。

コアとなるコードの変更箇所

src/pkg/net/http/server.goファイルが変更されています。

--- a/src/pkg/net/http/server.go
+++ b/src/pkg/net/http/server.go
@@ -12,7 +12,6 @@ package http
 import (
 	"bufio"
 	"bytes"
-	"crypto/rand"
 	"crypto/tls"
 	"errors"
 	"fmt"
@@ -985,6 +984,7 @@ type Server struct {
 	ReadTimeout    time.Duration // maximum duration before timing out read of the request
 	WriteTimeout   time.Duration // maximum duration before timing out write of the response
 	MaxHeaderBytes int           // maximum size of request headers, DefaultMaxHeaderBytes if 0
+	TLSConfig      *tls.Config   // optional TLS config, used by ListenAndServeTLS
 }
 
 // ListenAndServe listens on the TCP network address srv.Addr and then
@@ -1121,9 +1121,12 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
 	if addr == "" {
 		addr = ":https"
 	}
-	config := &tls.Config{
-		Rand:       rand.Reader,
-		NextProtos: []string{"http/1.1"},
+	config := &tls.Config{}
+	if srv.TLSConfig != nil {
+		*config = *srv.TLSConfig
+	}
+	if config.NextProtos == nil {
+		config.NextProtos = []string{"http/1.1"}
 	}
 
 	var err error

コアとなるコードの解説

  1. crypto/randのインポート削除:

    -	"crypto/rand"
    

    tls.ConfigRandフィールドは、デフォルトでcrypto/rand.Readerが使用されるため、net/http/server.go内で明示的にインポートする必要がなくなりました。これは、tls.Configの内部的なデフォルト値に依存することで、コードの依存関係を減らす変更です。

  2. http.Server構造体へのTLSConfigフィールドの追加:

    +	TLSConfig      *tls.Config   // optional TLS config, used by ListenAndServeTLS
    

    http.Server構造体にTLSConfigというポインタ型のフィールドが追加されました。このフィールドは*tls.Config型であり、ユーザーがカスタムのTLS設定をhttp.Serverインスタンスに直接割り当てられるようにします。コメントにもあるように、これはListenAndServeTLS関数によって使用されます。

  3. ListenAndServeTLS関数内のtls.Config初期化ロジックの変更:

    -	config := &tls.Config{
    -		Rand:       rand.Reader,
    -		NextProtos: []string{"http/1.1"},
    -	}
    +	config := &tls.Config{}
    +	if srv.TLSConfig != nil {
    +		*config = *srv.TLSConfig
    +	}
    +	if config.NextProtos == nil {
    +		config.NextProtos = []string{"http/1.1"}
    +	}
    
    • 以前は、ListenAndServeTLS内で新しいtls.Configがハードコードされたデフォルト値(Rand: rand.Reader, NextProtos: []string{"http/1.1"})で初期化されていました。
    • 変更後、まず空のtls.Configが作成されます (config := &tls.Config{})。
    • 次に、if srv.TLSConfig != nilの条件で、http.ServerインスタンスにTLSConfigが設定されているかを確認します。
    • もし設定されていれば、*config = *srv.TLSConfigによって、srv.TLSConfigの内容が新しく作成されたconfigにコピーされます。これにより、ユーザーが指定したカスタム設定が反映されます。
    • 最後に、if config.NextProtos == nilの条件で、configNextProtosフィールドがまだ設定されていない場合(つまり、ユーザーがカスタムTLSConfigNextProtosを指定しなかった場合)、デフォルト値である[]string{"http/1.1"}が設定されます。これは、ALPNのネゴシエーションにおいてHTTP/1.1が常にサポートされるようにするためのものです。

この一連の変更により、ListenAndServeTLSは、ユーザーがhttp.Server.TLSConfigに設定した詳細なTLS設定を尊重しつつ、基本的なALPNプロトコル(HTTP/1.1)の互換性も維持するようになりました。

関連リンク

  • https://golang.org/cl/5688047 - このコミットに対応するGoのコードレビューシステム(Gerrit)のチェンジリスト。詳細な議論や変更の経緯が確認できます。

参考にした情報源リンク