Skip to content

Widget→Receiver 取り込みのペア認証と受信データの安全な取り扱い #44

Description

@kosako

背景

POST /feedback は誰からでも・どこからでも受け付ける。公開デプロイすると spam / ゴミデータ / 悪意ある payload の投入が可能になり、受け取り側にもリスクがある(後述の SVG の件など)。widget と receiver の間に「ペア認証」的な仕組みが欲しい。

前提の整理

公開デモページに埋める widget はブラウザで動くため、埋め込んだキーは閲覧者全員に見える。したがってここでの ingest key は「秘密による認証」ではなく、(a) プロジェクト識別、(b) 無差別 spam の抑止、(c) キーのローテーションによる失効、を目的とした軽量な仕組みになる。本気のレビュアー認証はデモ側にログインがある前提で署名付き token を発行する形(将来スコープ)。

スコープ

ペア認証(ingest key)

  • widget init に ingestKey(プロジェクトごとの公開キー)を追加し、payload またはヘッダーで送る
  • receiver 側 config に許可キーのリストを持ち、不一致は 401/403 で拒否
  • キーごとに projectId を紐付けてもよい(payload の projectId 詐称対策)

受信データの安全な取り扱い

  • screenshot SVG の stored XSS 対策(重要): 保存した SVG は <script>onload を含み得る。inbox の <img> 表示では実行されないが、GET /screenshots/:file を直接開くと receiver オリジンで実行される。対策候補:
    • 配信時に Content-Security-Policy: sandbox / script-src 'none' を付ける(最小・推奨)
    • もしくは Content-Disposition: attachment
    • もしくは保存時に SVG をサニタイズ(script / イベント属性 / foreignObject 内の危険要素除去は難しいので CSP 推奨)
  • Origin / Referer の allowlist チェック(CORS とは別にサーバー側でも検証)
  • rate limit(IP ごと / キーごと)と保存件数・ディスク使用量の上限
  • 既存の防御の維持: payload shape validation / MAX_BODY_BYTES / SCREENSHOT_MAX_BYTES / mime type 制限 / inbox の HTML escape

受け入れ条件

  • ingest key を設定した receiver は、キーなし・不正キーの POST /feedback を拒否する
  • ローカル開発(キーなし運用)は引き続き動く
  • screenshot を直接開いても script が実行されない
  • README に設定方法が記載されている

関連

  • 管理面(inbox 閲覧・操作)の認証は別 issue(公開デプロイ時のハードニング)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions