GoにおけるTLSの完全なガイド:フルプロセスを解説
May 23, 2025
# golang
Olivia Novak
Dev Intern · Leapcell

TLSハンドシェイクプロセスの説明
TLS(Transport Layer Security)ハンドシェイクは、クライアント(Webブラウザなど)とサーバー(Webサーバーなど)間の安全な通信を可能にする重要な手順です。以下は、TLSハンドシェイクプロセス全体の詳細な内訳です。
-
クライアントHello
- クライアントは、サーバーに「クライアントHello」メッセージを送信してハンドシェイクを開始します。
- このメッセージには以下が含まれます。
- クライアントがサポートするTLSバージョン。
- サポートする暗号スイート(暗号化アルゴリズム)のリスト。
- ランダムなバイト文字列(クライアントランダムと呼ばれます)。
-
サーバーHello
- サーバーは、「サーバーHello」メッセージで応答します。
- このメッセージには以下が含まれます。
- 選択されたTLSバージョン。
- 選択された暗号スイート。
- ランダムなバイト文字列(サーバーランダムとして知られています)。
- サーバーのデジタル証明書(信頼できる認証局(CA)によって発行されます)。
-
証明書の検証
- クライアントは、認証局(CA)チェーンを通じてサーバーの証明書を検証します。
- 証明書が有効であり、期限切れではなく、正しいドメインに発行されていることを確認します。
-
プレマスターシークレットの生成
- クライアントは、サーバーの公開キー(証明書から抽出)を使用して「プレマスターシークレット」を生成します。
- このシークレットは暗号化され、サーバーに送信されます。
-
マスターシークレットの導出
- クライアントとサーバーの両方が、以下を使用して「マスターシークレット」を生成します。
- クライアントランダム。
- サーバーランダム。
- プレマスターシークレット。
- マスターシークレットは、暗号化と整合性チェックのためにセッションキーを導出するために使用されます。
- クライアントとサーバーの両方が、以下を使用して「マスターシークレット」を生成します。
-
セッションキーの作成
- マスターシークレットを使用して、両当事者は以下を作成します。
- 対称暗号化のための暗号化キー。
- 整合性チェックのためのMAC(メッセージ認証コード)キー。
- マスターシークレットを使用して、両当事者は以下を作成します。
-
クライアント完了
- クライアントは、セッションキーで暗号化された「完了」メッセージを送信します。
- これは、ハンドシェイクが成功し、今後のメッセージが暗号化されることを確認します。
-
サーバー完了
- サーバーは、セッションキーで暗号化された独自の「完了」メッセージを送信します。
- これにより、ハンドシェイクの終了と暗号化された通信の開始がマークされます。
-
データ転送
- 後続のすべての通信は、導出されたセッションキーを使用して暗号化されます。
- データは、整合性チェックを含む暗号化されたパケットで送信されます。
TLSハンドシェイクプロセスの図
+----------------------------------------+ +----------------------------------------+
| クライアント | | サーバー |
+----------------------------------------+ +----------------------------------------+
| | | |
| ClientHello |----->| |
| [TLSバージョン、暗号スイート、ランダム] | | |
| | | |
| | | ServerHello |
| |<-----| [TLSバージョン、暗号スイート、ランダム] |
| | | |
| |<-----| 証明書 |
| | | [サーバーの公開キー] |
| | | |
| |<-----| ServerHelloDone |
| | | |
| CertificateVerify | |
| [サーバーの証明書を検証] | | |
| | | |
| ClientKeyExchange |----->| |
| [暗号化されたプレマスターシークレット] | | |
| | | |
| ChangeCipherSpec |----->| |
| [Start Using Encryption] | | |
| | | |
| Finished |----->| |
| [ハンドシェイクの整合性を検証] | | |
| | | |
| |<-----| ChangeCipherSpec |
| | | [暗号化の使用を開始] |
| | | |
| |<-----| Finished |
| | | [ハンドシェイクの整合性を検証] |
| | | |
| 安全な通信 |<--->| 安全な通信 |
| [暗号化されたデータ転送] | | [暗号化されたデータ転送] |
+----------------------------------------+ +----------------------------------------+
GoLangでTLSクライアントHelloメッセージを取得する
以下に、GoLangを使用してすべてのClientHelloメッセージをキャプチャするサーバーを実装する方法を示します。
証明書の生成
まず、必要なSSL証明書を生成します。
# 秘密鍵を生成する openssl genrsa -out server.key 2048 # 公開鍵(証明書)を生成する openssl req -new -x509 -key server.key -out server.pem -days 3650
サーバー実装
以下は、ClientHello情報をキャプチャするための完全なサーバーコードです。
package main import ( "bufio" "crypto/tls" "encoding/json" "fmt" "io/ioutil" "log" "net" "os" "sync" "time" ) type CollectInfos struct { ClientHellos []*tls.ClientHelloInfo sync.Mutex } var collectInfos CollectInfos var currentClientHello *tls.ClientHelloInfo func (c *CollectInfos) collectClientHello(clientHello *tls.ClientHelloInfo) { c.Lock() defer c.Unlock() c.ClientHellos = append(c.ClientHellos, clientHello) } func (c *CollectInfos) DumpInfo() { c.Lock() defer c.Unlock() data, err := json.Marshal(c.ClientHellos) if err != nil { log.Fatal(err) } ioutil.WriteFile("hello.json", data, os.ModePerm) } func getCert() *tls.Certificate { cert, err := tls.LoadX509KeyPair("server.pem", "server.key") if err != nil { log.Println(err) return nil } return &cert } func buildTlsConfig(cert *tls.Certificate) *tls.Config { cfg := &tls.Config{ Certificates: []tls.Certificate{*cert}, GetConfigForClient: func(clientHello *tls.ClientHelloInfo) (*tls.Config, error) { collectInfos.collectClientHello(clientHello) currentClientHello = clientHello return nil, nil }, } return cfg } func serve(cfg *tls.Config) { ln, err := tls.Listen("tcp", ":443", cfg) if err != nil { log.Println(err) return } defer ln.Close() for { conn, err := ln.Accept() if err != nil { log.Println(err) continue } go handler(conn) } } func handler(conn net.Conn) { defer conn.Close() r := bufio.NewReader(conn) for { msg, err := r.ReadString('\n') if err != nil { log.Println(err) return } fmt.Println(msg) data, err := json.Marshal(currentClientHello) if err != nil { log.Fatal(err) } _, err = conn.Write(data) if err != nil { log.Println(err) return } } } func main() { go func() { for { collectInfos.DumpInfo() time.Sleep(10 * time.Second) } }() cert := getCert() if cert != nil { serve(buildTlsConfig(cert)) } }
クライアント実装
対応するクライアントコードは次のとおりです。
func main() { conn, err := tls.Dial("tcp", "localhost:443", &tls.Config{InsecureSkipVerify: true}) if err != nil { log.Fatal(err) } defer conn.Close() _, err = conn.Write([]byte("hello\n")) if err != nil { log.Fatal(err) } buf := make([]byte, 1000) n, err := conn.Read(buf) if err != nil { log.Fatal(err) } fmt.Println(string(buf[:n])) }
この実装により、TLSハンドシェイクプロセス中にClientHelloメッセージから詳細な情報をキャプチャできます。サーバーは、分析のためにこの情報をJSONファイルに定期的にエクスポートします。
Leapcell:最高のサーバーレスWebホスティング
最後に、Goサービスのデプロイに最適なプラットフォームをお勧めします:Leapcell
🚀 お気に入りの言語で構築
JavaScript、Python、Go、またはRustで簡単に開発できます。
🌍 無制限のプロジェクトを無料でデプロイ
使用量に応じてのみ料金を支払います。リクエストがない場合は料金はかかりません。
⚡ 従量課金制、隠れたコストなし
アイドル料金はなく、シームレスなスケーラビリティのみです。
🔹 Twitterでフォローしてください:@LeapcellHQ