【実務・中級編】CSP報告用エンドポイント(report-uri/report-to)の構築 – アプリケーションセキュリティ & 安全な開発防御ガイド

穴の開いたバケツで水を汲むな:CSPレポートエンドポイントを「攻撃者の踏み台」にしないための鉄則

現場でインシデント対応をしていると、セキュリティ設定を「とりあえず有効化した」だけの状態で放置しているシステムに頻繁に遭遇する。特にCSP(Content Security Policy)の導入は、XSS対策の切り札として推奨されるが、「違反レポートを受け取るためのエンドポイント」自体を脆弱なまま放置しているケースが驚くほど多い。

君たちが「攻撃の予兆を検知するため」に作ったはずのレポート受信サーバーが、実は攻撃者に悪用される「攻撃用の踏み台」や「負荷分散攻撃の標的」になっているとしたら、笑い話にもならないだろう。今日は、CSPレポートエンドポイントを堅牢に構築し、真の意味で「戦える監視基盤」にするための技術を叩き込む。

—

なぜCSPレポートエンドポイントが狙われるのか?

CSPレポート(report-uri / report-to)は、ブラウザが違反を検知した際に、JSON形式のデータを指定されたURLにPOSTする仕組みだ。攻撃者はここを次のように悪用する。

1. POSTによるDoS攻撃: エンドポイントに大量の不正なJSONを投げつけ、バックエンドのデータベースやログ収集基盤をパンクさせる。
2. インジェクションの踏み台: レポート内容を偽装し、ログ収集用のDBに対してSQLインジェクションやOSコマンドインジェクションを仕掛ける(ログ解析ツールが脆弱な場合、そこが突破口になる)。
3. 情報漏洩: 意図的に違反を発生させ、レポート内容に含まれる機密性の高いURLパラメータや認証トークンを収集する。

つまり、「外部からPOSTを受け取る」という行為自体が、すでにハイリスクな操作であることを肝に銘じてほしい。

—

堅牢な実装サンプル:Goによる超軽量・高耐久レシーバー

PHPやPythonでも実装は可能だが、大量のトラフィックをさばきつつ、メモリ消費を抑え、型安全性を確保するという観点から、今回はGoでの実装例を示す。このコードは、「入力を徹底的にバリデートし、即座に安全なログへ落とし込む」ことに特化している。

実装コード(main.go)

package main

import (
“encoding/json”
“log”
“net/http”
)

// 受信するCSPレポートの構造体を厳密に定義する
type CSPReport struct {
Report struct {
DocumentURI string json:"document-uri"
BlockedURI string json:"blocked-uri"
ViolatedDir string json:"violated-directive"
} json:"csp-report"
}

func reportHandler(w http.ResponseWriter, r http.Request) {
if r.Method != http.MethodPost {
http.Error(w, “Method Not Allowed”, http.StatusMethodNotAllowed)
return
}

// 1. レスポンスボディのサイズを制限(DoS対策)
r.Body = http.MaxBytesReader(w, r.Body, 102410)

var report CSPReport
if err := json.NewDecoder(r.Body).Decode(&report); err != nil {
http.Error(w, “Bad Request”, http.StatusBadRequest)
return
}

// 2. ログには構造化データとして出力し、インジェクションを防止する
// 直接DBに書き込まず、必ず標準出力経由でfluentd/logstash等へ渡す設計にする
log.Printf(“CSP_VIOLATION: doc=%s, blocked=%s, dir=%s”,
report.Report.DocumentURI, report.Report.BlockedURI, report.Report.ViolatedDir)

w.WriteHeader(http.StatusNoContent)
}

func main() {
http.HandleFunc(“/csp-report”, reportHandler)
log.Fatal(http.ListenAndServe(“:8080”, nil))
}

—

実務で不可欠な3つの防御レイヤー

コードを書くだけでは不十分だ。インフラレイヤーで以下の3点を必ず設定せよ。

1. WAF(Web Application Firewall)による保護

AWS WAFやCloudflareを使用している場合、レポートエンドポイントに対しては以下の設定を適用する。

  • リクエストレート制限: 特定のIPからのPOSTリクエストを1分間に数回程度に絞る。
  • シグネチャフィルタ: eval() や javascript: などの文字列が含まれる場合にブロックするルールを適用する。

2. Nginxでのリクエスト制限(Rate Limiting)

アプリケーションの手前でNginxをプロキシとして挟んでいるなら、以下の設定は必須だ。

limit_req_zone $binary_remote_addr zone=csp_limit:10m rate=5r/s;

server {
location /csp-report {
limit_req zone=csp_limit burst=10 nodelay;
proxy_pass http://localhost:8080;
}
}

3. セキュリティヘッダーの付与

レポートエンドポイント自体も、攻撃の踏み台にされないよう以下のヘッダーを付与する。

  • X-Content-Type-Options: nosniff
  • Content-Type: application/json (これ以外を受け付けない)

—

結論:監視は「受動的」であるべきではない

CSPレポートエンドポイントは、君たちの城を守るための「防犯カメラ」だ。しかし、カメラそのものが破壊されれば、侵入者はやりたい放題になる。

「外部からの入力を信用しない」というセキュリティの鉄則は、どんなに地味な監視用エンドポイントであっても例外ではない。今回紹介したバリデーションとレート制限を組み込み、ログ基盤自体を「セキュアなパイプライン」として設計すること。

もし、今動いている監視システムが「とりあえずログをDBに溜め込んでいるだけ」なら、今すぐ修正に着手してくれ。セキュリティは、コードを書き終えた後に始まるのではなく、アーキテクチャを決めた瞬間に勝負が決まっているのだから。

コメント

タイトルとURLをコピーしました