セキュリティ
私たちのセキュリティモデルを一言で言えば、攻撃対象となるサーバー上のものが何もないということです。以下の内容はすべて DevTools から検証できます。
アーキテクチャ
Abundera QR は Cloudflare Pages から配信される静的シングルページアプリケーションです。アプリケーションサーバー、データベース、ユーザーアカウント、認証、API エンドポイント、ユーザーデータを処理するバックエンドコードパスは一切存在しません。QR の生成、エンコード、スキャン、レンダリングのすべての処理はブラウザ内で完結します。
脅威モデル
ユーザーデータの収集、保存、送信を行わないため、最も一般的な Web アプリの脅威, 認証情報の窃取、データベース侵害、セッションハイジャック、サーバーサイドインジェクション, は適用されません。残る攻撃対象は、オリジンから配信される静的アセットバンドル(HTML、CSS、JavaScript)です。私たちは以下を前提に設計しています:
- オリジンの侵害:攻撃者がバンドルされたアセットの一つを悪意のあるものに置き換えるケース。以下の CSP がダメージを制限し、キャッシュバスタートークンによって既知の正常バージョンへの切り戻しが容易になります。
- ユーザー入力:QR ペイロード、vCard の名前、Wi-Fi パスワード、バッチ CSV の行、スキャン画像の内容。すべての入力パスは、DOM に戻してレンダリングされる際に信頼できないものとして扱われます。
- ユーザー提供の画像:vCard の写真 URL とロゴのアップロード。画像はキャンバスにレンダリングされ、生のマークアップとして DOM に埋め込まれることはありません。
- サードパーティのブラウザ拡張機能:対象外です。ブラウザの拡張機能がすべてのページを変更する権限を持っている場合、私たちのページも変更される可能性があります。私たちの保証は、ページが改変されていない状態で読み込まれた場合に有効です。
コンテンツセキュリティポリシー, ディレクティブ別
現在のポリシー(任意のリクエストのレスポンスヘッダーで確認できます):
Content-Security-Policy:
default-src 'self';
script-src 'self' 'wasm-unsafe-eval';
worker-src 'self' blob:;
style-src 'self' 'unsafe-inline';
font-src 'self';
img-src 'self' data: blob: https:;
connect-src 'self' https:;
frame-ancestors 'none';
base-uri 'self';
form-action 'self'各ディレクティブが許可する操作と妥協点:
default-src 'self', 基本方針。明示的に緩和しないものはすべて同一オリジンに制限されます。script-src 'self' 'wasm-unsafe-eval', インライン<script>およびeval()は禁止。'wasm-unsafe-eval'は QR エンコーダーライブラリの WebAssembly コンパイルパスに必要です。従来のeval()は許可されません。デプロイ前チェックがすべての HTML ページでインラインスクリプトをスキャンし、検出されるとビルドが失敗します。style-src 'self' 'unsafe-inline', 実際の妥協点。QR プレビューは個々のモジュールのスタイル属性でピクセルレベルの色をインラインで計算します。ハッシュベースの許可リストは機能しますが、デプロイなしのスタイル更新で失敗します。トレードオフ:わずかに弱いスタイルポリシーを受け入れます。スタイリングはデータを持ち出すことができません(CSS にはconnect-srcの到達範囲がありません)。img-src 'self' data: blob: https:,data:はインライン QR レンダリング用、blob:はエクスポートダウンロード URL 用、https:はユーザー提供の vCard 写真 URL 用。ユーザー提供の URL は実行されず、レンダリングのみされます。connect-src 'self' https:, fetch() は自オリジンとユーザーが起動した HTTPS フェッチ(写真 URL のスキャンなど)に制限されます。任意のホストへの DNS / WebSocket / ビーコン経由の情報漏洩を防ぎます。frame-ancestors 'none', 他のサイトが私たちを埋め込めません。クリックジャッキングを防ぎます。base-uri 'self', 悪意を持って注入された<base>タグが相対 URL を攻撃者のオリジンにリダイレクトすることを防ぎます。form-action 'self', 注入されたフォームは自オリジンにしかポストできません。サーバーサイドでデータを送信するフォームはありません。これはベルトとサスペンダーの対策です。
/bio/*(ユーザー提供アバター用に img-src を緩和)と /embed/*(意図的な埋め込み用に frame-ancestors を緩和)には異なる CSP ポリシーが適用されます。いずれも site/_headers に記載されています。
トランスポート + フレーミングヘッダー
- HSTS:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload, 1年間、すべてのサブドメイン、HSTS プリロードリストの対象。準拠ブラウザは HTTP へのダウングレードを拒否します。 - X-Frame-Options: DENY, CSP の
frame-ancestorsと重複しますが、古いブラウザのカバレッジのために維持されています。 - X-Content-Type-Options: nosniff, MIME 混乱攻撃を防ぎます。
- Referrer-Policy: strict-origin-when-cross-origin, 外部リンクのクリックはオリジンを漏洩しますが、パスは漏洩しません。
- Permissions-Policy:
camera=(self), microphone=(), geolocation=(), カメラは自前のスキャナーのみ許可、マイクと位置情報は埋め込まれた場合でも明示的に拒否されます。
サービスワーカー
サービスワーカー(site/sw.js)は同一オリジンのアセットのみをキャッシュします。フェッチハンドラーはクロスオリジンリクエストと GET 以外のメソッドを明示的に拒否します, ロジックは GitHub で確認できます。キャッシュへの書き込みは event.waitUntil() でラップされているため、ナビゲーション中に破棄されることはありません。
入力サニタイズ
ユーザー入力を受け付けるすべてのレンダリングパスは、それを信頼できないテキストとして扱います:
- QR ペイロードプレビューは
innerHTMLではなくtextContentを使用します。 - 共有ターゲット(クリップボード、
navigator.share())はユーザーテキストをマークアップとしてではなく文字列として渡します。 - SVG エクスポートはエンコーダーライブラリから生成されます。ユーザーコンテンツは SVG 要素として注入されるのではなく、
<image>のxlink:hrefに base64 エンコードされます。 - 印刷プレビューは
document.write()ではなく blob URL を使用します。 - localStorage の解析は
try/catchでラップされています, 壊れたエントリは、ライブコードパスに展開される可能性のある例外ではなく、新しい空のデフォルト値を返します。 - "リンクを開く" ボタンとして表示されるユーザー提供の URL は
http(s)://に制限されています,javascript:およびdata:スキームは拒否されます。
クロスオリジン画像フェッチ
ユーザーが vCard 写真またはロゴとして https: URL を貼り付けると、ブラウザは CORS と CSP の img-src 許可リストに従ってフェッチします。画像はキャンバスにレンダリングされます。ライブ DOM になることも、コードとして実行されることも、私たちのオリジンに到達することもありません, フェッチはブラウザ → リモート画像で行われ、結果はクライアントサイドで描画されます。リモート画像 URL を制御する攻撃者は、その URL が読み込まれたことを追跡できます(自分のサーバーのログ行)が、私たちのページから何かを持ち出すことはできません。
サブリソース整合性(SRI)
私たちが提供するすべての JavaScript と CSS は同一オリジンです。サードパーティのスクリプトやスタイルシートを読み込まないため、SRI ハッシュは適用されません。将来サードパーティのアセットを読み込む場合は、integrity 属性を付与し、このページにハッシュ更新プロセスを記載します。
脆弱性の報告
Abundera QR に影響するセキュリティ問題(コード、デプロイメント、または同梱の依存関係のいずれか)を発見した場合は、security@abundera.ai に非公開で報告してください。72時間以内のトリアージを目指しています。/.well-known/security.txt ファイルの連絡先からも連絡できます。
バグバウンティについて(現時点では未実施)
現在、有償バウンティは提供していませんが、確認された有効な報告はすべて変更履歴と公開の謝辞でクレジットされます。
上記の内容を検証する
このページのすべての主張は、私たちを信頼することなくブラウザの DevTools から検証できます:
- CSP:DevTools → ネットワーク →
/→ ヘッダー。Content-Security-Policyレスポンスヘッダーを確認してください。 - HSTS + セキュリティヘッダー:同じ場所,
Strict-Transport-Security、X-Frame-Optionsなどがすべて表示されます。 - 外部通信なし:DevTools → ネットワーク → Fetch/XHR。QR を生成してください。カウントがゼロのままであることを確認してください。
- サービスワーカーのスコープ:DevTools → アプリケーション → Service Workers。スクリプトソースとキャッシュされたアセットリストを確認してください。
- Cookie なし:DevTools → アプリケーション → Cookie。空です。
- 完全なウォークスルー:マニフェストの検証セクション。
連絡先
セキュリティに関する開示:security@abundera.ai