oka-project since 2024 お問い合わせ
TOPブログ / 技術

ブラウザ完結ツールの「送信しない」を、約束ではなく構造にする

2026.08.24 公開 技術 約2分で読めます

「データを送信しません」と書くのは簡単ですが、証明はできません。CSPを使って「送信できない」構造を作り、実際に流出経路を1つ見つけて塞ぐまでの記録です。

「送信しません」は検証できない

tools.oka-project.com のツールは、入力されたデータを一切外部へ送信しない方針で作っています。ただ「送信しません」と書くだけなら誰にでもできます。利用者から見れば、それは約束であって証明ではありません。

そこで、送信しないではなく送信できない構造にすることにしました。

CSPで通信手段そのものを断つ

Content-Security-Policy(CSP)というブラウザの仕組みを使うと、ページ内のJavaScriptが使える通信手段を配信時に宣言できます。

default-src 'none'; script-src 'self'; style-src 'self';
font-src 'self'; img-src 'self' data:;

default-src 'none' を基点にすると、明示的に許可していないものはすべて禁止になります。fetch も XHR も WebSocket も使えません。重要なのは、これを強制するのはブラウザであって、サイト運営者ではないという点です。私たち自身にも解除できません。

それでも1つ、穴があった

公開後の監査で、実際に流出経路を1つ見つけました。当初の設定は画像だけ img-src ... https: と緩めてあり、任意のhttpsサイトから画像を読み込めたのです。

Markdownを表示するツールでこれは問題になります。悪意あるファイルに

![](https://attacker.example/pixel.png)

という1行があるだけで、開いた瞬間に相手のサーバーへリクエストが飛び、IPアドレスとブラウザ情報が渡ります。

対処は二段にしました。CSPを img-src 'self' data: に締めてブラウザ側で遮断し、さらに表示処理でも外部画像のURLを外して「なぜ読み込まなかったか」を説明するプレースホルダに置き換えました。壊れた画像アイコンを見せるのではなく、遮断そのものを機能として見せる形です。

学んだこと

  • 宣言と構造は別物。 構造にすると、利用者が自分で検証できる(開発者ツールのNetworkタブを開けば通信ゼロが見える)
  • 緩めた1箇所は必ず突かれる前提で見る。 https: を1つ許しただけで約束が破れていた
  • 遮断は隠さず見せる。 何が起きたか説明すれば、制限が信頼の材料になる

この方針はツール追加の手順書にも組み込んだので、今後つくるツールにも同じ構造が適用されます。

#CSP#セキュリティ#ブラウザ完結#tools
← ブログ一覧へ