0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Go言語でのTLSを徹底解説:全体の流れを一気に把握

Posted at

Group2253.png

Leapcell: The Best of Serverless Web Hosting

TLS ハンドシェイク プロセスの説明

TLS(Transport Layer Security)ハンドシェイクは、クライアント(Web ブラウザなど)とサーバー(Web サーバーなど)間の安全な通信を確立するための重要なプロセスです。以下に、TLS ハンドシェイクの全体の流れを詳細に分解します:

  1. クライアント Hello

    • クライアントは「Client Hello」メッセージをサーバーに送信してハンドシェイクを開始します。
    • このメッセージには以下が含まれます:
      • クライアントがサポートする TLS バージョン。
      • サポートする暗号スイート(暗号化アルゴリズム)のリスト。
      • ランダムなバイト列(Client Random と呼ばれます)。
  2. サーバー Hello

    • サーバーは「Server Hello」メッセージで応答します。
    • このメッセージには以下が含まれます:
      • 選択された TLS バージョン。
      • 選択された暗号スイート。
      • ランダムなバイト列(Server Random と呼ばれます)。
      • サーバーのデジタル証明書(信頼された証明書発行機関(CA)によって発行されたもの)。
  3. 証明書の検証

    • クライアントは、証明書発行機関(CA)チェーンを通じてサーバーの証明書を検証します。
    • 証明書が有効であり、有効期限内であり、正しいドメインに発行されていることを確認します。
  4. プレマスター シークレットの生成

    • クライアントは、サーバーの公開鍵(証明書から抽出)を使用して「Pre-Master Secret」を生成します。
    • このシークレットは暗号化されてサーバーに送信されます。
  5. マスター シークレットの導出

    • クライアントとサーバーの両方が、以下を使用して「Master Secret」を生成します:
      • Client Random。
      • Server Random。
      • Pre-Master Secret。
    • Master Secret は、暗号化と整合性チェックのためのセッション キーを導出するために使用されます。
  6. セッション キーの作成

    • Master Secret を使用して、両者は以下を作成します:
      • 対称暗号化用の暗号化キー。
      • 整合性チェック用の MAC(Message Authentication Code)キー。
  7. クライアント Finished

    • クライアントは、セッション キーで暗号化された「Finished」メッセージを送信します。
    • これにより、ハンドシェイクが正常に完了し、以降のメッセージが暗号化されることが確認されます。
  8. サーバー Finished

    • サーバーもまた、セッション キーで暗号化された「Finished」メッセージを送信します。
    • これによりハンドシェイクが終了し、暗号化された通信が開始されます。
  9. データ転送

    • 以降のすべての通信は、導出されたセッション キーを使用して暗号化されます。
    • データは、整合性チェック付きの暗号化パケットで送信されます。

TLS ハンドシェイク プロセスの図

+----------------------------------------+      +----------------------------------------+
|               クライアント                   |      |               サーバー                   |
+----------------------------------------+      +----------------------------------------+
|                                        |      |                                        |
|  ClientHello                           |----->|                                        |
|  [TLS バージョン, 暗号スイート, ランダム]  |      |                                        |
|                                        |      |                                        |
|                                        |      |  ServerHello                            |
|                                        |<-----|  [TLS バージョン, 暗号スイート, ランダム]  |
|                                        |      |                                        |
|                                        |<-----|  Certificate                           |
|                                        |      |  [サーバーの公開鍵]                 |
|                                        |      |                                        |
|                                        |<-----|  ServerHelloDone                       |
|                                        |      |                                        |
|  CertificateVerify                     |      |                                        |
|  [サーバーの証明書を検証]         |      |                                        |
|                                        |      |                                        |
|  ClientKeyExchange                     |----->|                                        |
|  [暗号化された Pre-Master Secret]         |      |                                        |
|                                        |      |                                        |
|  ChangeCipherSpec                      |----->|                                        |
|  [暗号化の使用開始]              |      |                                        |
|                                        |      |                                        |
|  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: The Best of Serverless Web Hosting

最後に、Go サービスのデプロイに最適なプラットフォームをおすすめします: Leapcell

brandpic7.png

🚀 好きな言語で開発

JavaScript、Python、Go、Rust で簡単に開発できます。

🌍 無制限のプロジェクトを無料でデプロイ

使用分のみ課金—リクエストがない場合は無料です。

⚡ 使った分だけ課金、隠れた料金はありません

アイドル料金など一切なく、シームレスにスケーリング可能です。

Frame3-withpadding2x.png

📖 ドキュメントを確認する

🔹 Twitter でフォロー: @LeapcellHQ

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?