説明
要求と応答が TLS で保護されていない HTTP を通ると、通信経路上で内容を読み取られる可能性があります。同じネットワーク上や通信の中継地点にいる攻撃者が、パケットの盗聴や中間者攻撃によってログイン情報、セッション Cookie、個人情報などを盗むおそれがあります。
想定される影響
- 暗号化されずに送信された認証情報、セッショントークン、個人情報の漏えい
- 盗まれたパスワードや Cookie によるなりすまし、セッションの乗っ取り
- 決済情報や応答内容など、要求と応答の改ざん
- 信頼の低下や、PCI-DSS など適用されるプライバシー・セキュリティ要件への不適合
対処方法
- Go が外部の TLS 接続を直接終端するなら、
http.ListenAndServeTLSを使ってください。信頼するリバースプロキシが終端する場合は、外部の HTTPS と、プロキシからアプリケーションまでの経路の保護を確認してください。 - 信頼する CA の証明書を使ってください。開発・内部環境で自己署名証明書を使う場合も、信頼設定を適切に管理してください。
- HTTPS 応答に
Strict-Transport-Securityを設定してください。ブラウザーがポリシーを知る前の最初の HTTP 要求まで保護するものではありません。 - HTTP ポート(例: 80)は HTTPS(例: 443)への案内だけに使ってください。リダイレクト前に送信された認証情報や Cookie は保護できないため、機密性の高い要求は最初から HTTPS で送ってください。
- 機密情報の送信を必要最小限にし、機密性の高い Cookie に
Secureを設定してください。
例
変更前
go
package main
import (
"log"
"net/http"
)
func loginHandler(w http.ResponseWriter, r *http.Request) {
// 簡略化した例: 実際の認証ではパスワード検証などが必要
username := r.FormValue("username")
password := r.FormValue("password")
// 平文の HTTP では username と password が通信中に露出する可能性
log.Printf("login attempt: %s / %s", username, password)
w.Write([]byte("ok"))
}
func main() {
http.HandleFunc("/login", loginHandler)
// 変更前: TLS なしで HTTP を提供
// 要求と応答が平文で送信される
if err := http.ListenAndServe(":80", nil); err != nil {
log.Fatal(err)
}
}
変更後
go
package main
import (
"log"
"net/http"
"net/url"
)
func loginHandler(w http.ResponseWriter, r *http.Request) {
// 実際のサービスでは別途、認証と検証が必要
username := r.FormValue("username")
log.Printf("login attempt for username=%q", username)
w.Write([]byte("ok"))
}
func main() {
http.HandleFunc("/login", loginHandler)
// ポート 80 は HTTPS へのリダイレクトにだけ使用
go func() {
if err := http.ListenAndServe(":80", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
target := (&url.URL{
Scheme: "https",
Host: "www.example.com", // デプロイ設定で固定した HTTPS ホスト
Path: r.URL.Path,
RawQuery: r.URL.RawQuery,
}).String()
http.Redirect(w, r, target, http.StatusMovedPermanently)
})); err != nil {
log.Fatal(err)
}
}()
// 変更後: 実際の証明書と鍵ファイルのパスで TLS を設定
if err := http.ListenAndServeTLS(":443", "cert.pem", "key.pem", nil); err != nil {
log.Fatal(err)
}
}
説明:
- 変更前:
http.ListenAndServeは/loginを平文の HTTP で提供します。ログイン情報を通信中に盗まれる可能性があり、この例ではパスワードも不適切にログへ記録しています。 - 変更後:
http.ListenAndServeTLSで HTTPS を提供し、リダイレクト先には要求のHostではなく設定済みの固定ホストを使います。ユーザー名は%qで引用して制御文字によるログ構造の破壊を防ぎ、パスワードは記録しません。