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の実装
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.crt
とserver.key
が生成される。
これらのファイルをGo言語のHTTPSサーバー実装で使用することで、開発環境でHTTPS接続をテストできる。
自己署名証明書を使用する場合、ブラウザはその証明書を信頼しないため
「この接続は安全ではありません」という警告が表示される可能性がある。
server.crt
とserver.key
はGitHubなどにはあげない
ListenAndServerTLS
関数を使用して、HTTPSサーバーを起動します。
server.crt
とserver.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
を実行しリクエストを送ると、次のようなものが確認できました。
「 Hello HTTP World! 」というレスポンスが返ってきているのが、丸見えです。
今回はこのメッセージが見られたところで何の問題もありませんが、パスワードなど秘密情報だと思うと、怖いですね。
HTTPS通信の監視結果
同様に、Wiresharkを開いたら、キャプチャインターフェースとしてループバックインターフェース( lo0
)を選択する。
また、情報が見やすいようにtcp.port==443
でフィルタリングをしておきます。
そして、Go言語で実装したコードを実行して、HTTPSサーバーを起動します。
ターミナルでcurl -k https://localhost:443
を実行しリクエストを送ると、次のようなものが確認できました。
「 Hello HTTPS World! 」というメッセージを見つけることはできませんでした。
Length: 19
これは、続く暗号化されたアプリケーションのデータの長さをバイトで示しています。
Encrypted Application Data
実際のアプリケーションデータは暗号化されており、不規則な文字列として扱われている。
まとめ
今回は、HTTPとHTTPSの基本的な概念、両者のGo言語による簡易的な実装、およびWiresharkを使用して通信の監視をしました。
HTTPは基本的なWeb通信プロトコルであり、データは暗号化されずに送信される。これに対し、HTTPSはSSL/TLSプロトコルを使用してデータを暗号化することにより、より安全な通信を実現する。
実際のコード例を通じて、Go言語を使用した簡単なHTTPサーバーとHTTPSサーバーの構築方法を学びました。
さらに、Wiresharkを用いた実際の通信監視を通して、HTTPSがいかに通信を保護しているかを視覚的に確認することができました。