RAKUS Developers Blog | ラクス エンジニアブログ

株式会社ラクスのITエンジニアによる技術ブログです。

Wiresharkで観察して理解するHTTPS(HTTP over TLS)の仕組み

はじめに

エンジニア2年目のTKDSです!
普段何気なく使ってるほとんどのWebサイトが対応しているHTTPS通信の仕組みについて調べてみました。
本記事では、Wiresharkを用いてHTTPSの内部動作を解析し、どのようにしてデータが保護されているのかを具体的に解説します。
記事の後半では、Wiresharkを使って実際の通信データを観察し、暗号化プロセスの詳細を確認してみます。

HTTPS(HTTP Over TLS)とは

HTTPS(HTTP Over TLS)は、HTTPの暗号化版で、ウェブサイトとブラウザ間の安全な通信を実現するプロトコルです。
TLSを使用して、HTTP通信を暗号化することで、データの機密性、データの整合性、通信先サーバーの信頼性を確認できます。

SSL/TLS

SSL(Secure Sockets Layer)とTLS(Transport Layer Security)は、インターネット上でデータを暗号化して送受信するためのプロトコルです。
これらのプロトコルは、ウェブブラウザとウェブサーバー間の通信を保護し、データの盗聴や改ざんを防ぐために使用されます。

SSLは1990年代初頭にNetscape社によって開発されました。
最初のバージョンであるSSL 2.0は1995年にリリースされましたが、セキュリティ上の脆弱性が発見され、1996年にSSL 3.0に置き換えられました。
その後、1999年にSSL 3.0を基にしたTLS 1.0が登場し、現在ではTLS 1.3が最新バージョンとして使用されています。

HTTPSの流れ

HTTPSは次の流れで通信を行います。

  1. クライアントがサーバーにHTTPS接続を要求
  2. サーバーがSSL/TLS証明書(公開鍵も含む)をクライアントに送信
  3. クライアントが証明書を検証し、サーバーの身元を確認
  4. クライアントがセッション鍵(対称鍵)を生成
  5. クライアントがセッション鍵をサーバーの公開鍵で暗号化して送信
  6. サーバーが秘密鍵を使ってセッション鍵を復号、この時点で、クライアントとサーバーの両方が同じセッション鍵を共有、以降の通信はこのセッション鍵を使って暗号化
  7. クライアントが暗号化されたHTTPリクエストを送信
  8. サーバーがリクエストを復号して処理
  9. サーバーが暗号化されたHTTPレスポンスを送信
  10. クライアントがレスポンスを復号して表示

HTTPSの流れの図を以下に記載します。

暗号鍵をクライアントとサーバー間の通信で使うことで安全に通信していることがわかりました。

実際に通信を観察

次にHTTPSを観察してみます。
通信先のサーバーをGoで用意して、curlで通信します。

自己署名証明書の用意

今回使う証明書を用意します。

sudo apt-get update
sudo apt-get install openssl
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout server.key -out server.crt

サーバーの作成

今回使用するhttpサーバーを用意します。
ファイル名はmain.goを想定しています。
起動は、go run main.goで行ってください。

  • HTTPサーバー
package main

import (
    "fmt"
    "net/http"
)

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

func main() {
    http.HandleFunc("/", helloHandler)
    fmt.Println("Starting HTTP server on :8080")
    if err := http.ListenAndServe(":8080", nil); err != nil {
        fmt.Println("Error starting HTTP server:", err)
    }
}
  • HTTPSサーバー
package main

import (
    "fmt"
    "net/http"
)

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

func main() {
    http.HandleFunc("/", helloHandler)
    fmt.Println("Starting HTTPS server on :8443")
    if err := http.ListenAndServeTLS(":8443", "server.crt", "server.key", nil); err != nil {
        fmt.Println("Error starting HTTPS server:", err)
    }
}

WireSharkの準備

通信のキャプチャはWireSharkを使います。
以下の手順にしたがって準備してください。

  • インストール
sudo apt-get update
sudo apt-get install wireshark
sudo dpkg-reconfigure wireshark-common
sudo usermod -aG wireshark $USER
newgrp wireshark
  • èµ·å‹•
sudo wireshark
  • キャプチャするネットワークインターフェースの選択
    今回はlocalhostなので、loを選択します。

  • キャプチャの開始 開始ボタンを押すとキャプチャが開始されます。
    HTTPの場合、上部のフィルタにhttp.request and tcp.port == 8080を入力します。
    HTTPSの場合、上部のフィルタにtls and tcp.port == 8443と入力します。

リクエストを送信して観察

  • HTTP
    http用のサーバーを起動してからリクエストを送る。
    curl http://localhost:8080

通常のHTTP通信が行われているのが確認できます。

フィルタのhttp指定を外してすべての通信をみても、httpsではないので暗号化は行われていないことがわかります。

  • HTTPS
    HTTPS用のサーバーを起動してからリクエストを送る。
    curl -k https://localhost:8443

TLSハンドシェイクが行われていることが確認できます。
暗号化されているのでどのhttpメソッドを実行しているか、エンドポイントのパスはなにかなどは通信内容から読み取れなくなっています。

TLSの流れを少しみてみましょう。

  • Client Hello
    TLS(Transport Layer Security)接続の開始時にクライアントからサーバーに送信される最初のメッセージです。
    クライアントがサポートするセキュリティ設定をサーバーに通知し、サーバーとクライアントの間で使用する暗号化方法のネゴシエートを開始します。

  • Server Hello
    Server Helloをクライアントに送信し、使用するTLSのバージョン、暗号スイート、圧縮方法を確定します。

  • Change Cipher Spec, Application Data
    Change Cipher Specをクライアントに送信し、以降の通信が暗号化されることを通知

以上がTLSの流れでした。

まとめ

ここまで読んでいただきありがとうございました!
この記事ではHTTPとHTTPSの通信を観察し、通信内容を比較しました。
ふとした疑問から調べはじめた内容でしたが、知識の復習やツールの使い方を思い出す役に立ちました 。
普段意識せずに使っているものも、実際に調べてみることで、知識の定着につながりました。


Copyright © RAKUS Co., Ltd. All rights reserved.