Go言語でHTTPとHTTPSを実装してWiresharkで通信を監視してみた

HTTPとHTTPSを実装してWiresharkで通信を監視してみた

HTTPとHTTPSの違い

まずは、HTTPとHTTPSの違いについて、簡単にまとめます。

HTTPとは

HTTP(HyperText Transfer Protocol)は、Web上で情報を交換するためのプロトコルのこと。

このプロトコルを使用すると、Webブラウザとサーバー間でHTMLページや画像などのリソースをやり取りできる。

しかし、HTTPは暗号化されていないため、データは途中で第三者に盗聴されたり、改ざんされるリスクがある。

HTTPSとは

HTTPS(HTTP Secure)は、HTTPにセキュリティ層を追加したもの。

主に、SSL(Secure Sockets Layer)またはTLS(Transport Layer Security)プロトコルを使用してデータを暗号化する。

HTTPSを使用すると、クライアントとサーバー間の通信は暗号化されるため、第三者によるデータの盗聴や改ざんを防ぐことができる。

HTTPSが中間者攻撃を防ぐ仕組み

HTTPSの方が、安全ということは分かりました。

そして、HTTPSでは具体的に以下のように、セキュリティ性が高められている。

  • 暗号化:HTTPSは、データを暗号化することで、第三者がデータを盗聴しても内容を理解できないようにする。
  • 認証:クライアントは、サーバーが正しい証明書を持っていることを検証することで、接続しているのが本当に意図したサーバーであることを確認する。これにより、偽のサーバーに接続するリスクを減らしている。
  • データの安全性:データ転送中の改ざんを検出するために、送信されるデータには整合性チェックを行う。

Go言語で簡易的にHTTPとHTTPSを実装

Go言語を使用して、簡易的なHTTPとHTTPSを実装します。

HTTPの実装

main関数内で、http.Handlerを使用してルートパス(/)に対するリクエストハンドラを登録します。

HTTPリクエストを受け取った際にレスポンスとして、「Hello HTTP World!」というメッセージを返します。

package main

import (
	"fmt"
	"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Hello HTTP World!")
	})

	fmt.Println("http://localhost:8080 でサーバーを起動します。")
	if err := http.ListenAndServe(":8080", nil); err != nil {
		panic(err)
	}
}

HTTPSの実装

SSL/TLS証明書と秘密鍵を生成する

HTTPS通信を実装する場合、SSL/TLS証明書と秘密鍵が必要になる。

これらがインターネット上での安全なデータ転送を保証するための重要な要素となる。

  • SSL / TLS証明書
    サーバーの身元を証明し、クライアントとサーバー間で送受信される情報が暗号化されることを保証する。
    この証明書は信頼できる第三者機関によって発行され、サーバーの公開鍵、発行者の署名、証明書の有効期限などの情報が含まれている。
  • 秘密鍵
    SSL/TLS証明書に関連づけられた鍵で、サーバーにのみ知られているべきもの。
    公開鍵と秘密鍵のペアを使用して暗号化と複合化のプロセスが行われ、この鍵の秘匿性が通信の安全を保証する。
    公開鍵は証明書と共にクライアントに公開され、暗号化された通信を行うために使用される。
    しかし、その暗号化された通信を復号化するには秘密鍵が必要となり、これはサーバー側でのみ保持される。

本番環境では、信頼できる認証局から正式な証明書を取得するべきだが、開発用途では、自己署名証明書で大丈夫。

macOSでは、opensslコマンドを使用することで生成することができる。

openssl req -x509 -newkey rsa:4096 -sha256 -days 365 -nodes -keyout server.key -out server.crt -subj "/C=JP/ST=Tokyo/L=Tokyo/O=Example Company/CN=localhost"
  • x509:自己署名証明書を生成
  • newkey rsa:4096:新しいRSA 4096ビット鍵を生成
  • sha256:SHA-256ハッシュアルゴリズムを使用
  • days 365:証明書の有効期限を365日に設定
  • nodes:秘密鍵を暗号化せずに出力(開発用にはこれで問題ない)
  • keyout:生成される秘密鍵のファイル名を指定
  • out:生成される証明書のファイル名を指定
  • subj:証明書のサブジェクト情報を指定(この例では、国(C)にJP、州(ST)と市(L)にTokyo、組織(O)にExample Company、共通名(CN)にlocalhostを使用する)

このコマンドを実行した後、同じディレクトリにserver.crtserver.keyが生成される。

これらのファイルをGo言語のHTTPSサーバー実装で使用することで、開発環境でHTTPS接続をテストできる。

自己署名証明書を使用する場合、ブラウザはその証明書を信頼しないため
「この接続は安全ではありません」という警告が表示される可能性がある。

server.crtserver.keyはGitHubなどにはあげない

Go言語による実装

ListenAndServerTLS関数を使用して、HTTPSサーバーを起動します。

server.crtserver.keyは先ほど生成した、サーバーのSSL/TLS証明書と秘密鍵のファイルパスを指している。

package main

import (
    "fmt"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, HTTPS World!")
}

func main() {
    http.HandleFunc("/", handler)

    fmt.Println("Starting HTTPS server on :443...")
    err := http.ListenAndServeTLS(":443", "server.crt", "server.key", nil)
    if err != nil {
        fmt.Println("Error starting server: ", err)
    }
}

Wiresharkのインストール方法

Wiresharkとは、ネットワークトラフィックをキャプチャし、分析するための強力なツールのこと。

macOSでは、WiresharkをHomebrewによって、インストールしていく。(Homebrewに関しては今回省略します)

brew install --cask wireshark

このコマンドを実行することで、すでにアプリケーションにインストールが完了しました。

WiresharkによるHTTP通信とHTTPS通信の監視結果

HTTP通信とHTTPS通信を実際にWiresharkで監視をして、本当にHTTPS通信の方が安全なのかを確認していきます。

HTTP通信の監視結果

Wiresharkを開いたら、キャプチャインターフェースとしてループバックインターフェース( lo0 )を選択する。

また、情報が見やすいようにhttpでフィルタリングをしておきます。

そして、Go言語で実装したコードを実行して、HTTPサーバーを起動します。

ターミナルでcurl http://localhost:8080を実行しリクエストを送ると、次のようなものが確認できました。

WiresharkによってHTTP通信を監視した結果

「 Hello HTTP World! 」というレスポンスが返ってきているのが、丸見えです。

今回はこのメッセージが見られたところで何の問題もありませんが、パスワードなど秘密情報だと思うと、怖いですね。

HTTPS通信の監視結果

同様に、Wiresharkを開いたら、キャプチャインターフェースとしてループバックインターフェース( lo0 )を選択する。

また、情報が見やすいようにtcp.port==443でフィルタリングをしておきます。

そして、Go言語で実装したコードを実行して、HTTPSサーバーを起動します。

ターミナルでcurl -k https://localhost:443を実行しリクエストを送ると、次のようなものが確認できました。

Wiresharkによって、HTTPS通信を監視した結果

「 Hello HTTPS World! 」というメッセージを見つけることはできませんでした。

Length: 19これは、続く暗号化されたアプリケーションのデータの長さをバイトで示しています。

Encrypted Application Data実際のアプリケーションデータは暗号化されており、不規則な文字列として扱われている。

まとめ

今回は、HTTPとHTTPSの基本的な概念、両者のGo言語による簡易的な実装、およびWiresharkを使用して通信の監視をしました。

HTTPは基本的なWeb通信プロトコルであり、データは暗号化されずに送信される。これに対し、HTTPSはSSL/TLSプロトコルを使用してデータを暗号化することにより、より安全な通信を実現する。

実際のコード例を通じて、Go言語を使用した簡単なHTTPサーバーとHTTPSサーバーの構築方法を学びました。

さらに、Wiresharkを用いた実際の通信監視を通して、HTTPSがいかに通信を保護しているかを視覚的に確認することができました。