XSSのその先へ:Permissions Policyでブラウザを「要塞化」する実践ガイド
「XSS対策はサニタイズ(エスケープ)さえしていれば安心」――そう思っているなら、そろそろ考えを改めるべきだ。
現場でインシデント対応をしていると痛感するが、現代のWebアプリケーションにおいて、XSSは単なる「アラートボックスを表示させるいたずら」ではない。攻撃者は、ブラウザが持つ強力なAPI(カメラ、マイク、位置情報、支払機能など)を奪い取り、ユーザーのプライバシーを根こそぎ盗み出すことを狙っている。
もし、君たちが開発している管理画面や会員サイトに、たった一箇所でもクロスサイトスクリプティング(XSS)の脆弱性が残っていたらどうなるか。攻撃者は、ユーザーのブラウザを使ってカメラを勝手に起動し、盗撮を行うことも、マイクで会議を盗聴することも可能だ。
今日は、そんな「ブラウザAPIの悪用」を根絶するための最後の砦、Permissions Policyについて、実戦的な実装レベルで解説する。
—
1. なぜ「エスケープ」だけでは足りないのか?
XSSには反射型、格納型、DOM型の3種類があるが、どれであっても攻撃のゴールは「ブラウザ上で悪意あるスクリプトを実行すること」に変わりはない。
仮に、巧妙なDOM型XSSを突かれ、攻撃者のスクリプトが実行されたとする。その時、Permissions Policyが設定されていなければ、攻撃者は以下のようなAPIを自由に呼び出せる。
navigator.geolocation.getCurrentPosition()(現在地特定)navigator.mediaDevices.getUserMedia()(カメラ・マイクの権限奪取)paymentRequest(決済機能の不正操作)
これらはOSレベルでユーザーの許可を求めることもあるが、ソーシャルエンジニアリングを組み合わせられれば、ユーザーは気づかぬうちに「許可」を押させられる。これを防ぐには、「ブラウザ自体に、その機能を使う権利があるかを事前定義しておく」というOS的な発想が必要だ。
—
2. Permissions Policyの「守りの要」
Permissions Policy(旧Feature-Policy)は、HTTPレスポンスヘッダーとして送信することで、特定のオリジン(ドメイン)以外からの強力なブラウザ機能の利用を、ブラウザエンジンレベルで拒否する仕組みだ。
推奨される実装設定(Nginx)
設定はアプリケーションコードに書くよりも、Webサーバー(Nginx等)で一括制御するのが運用の鉄則だ。以下の設定を nginx.conf に追加してほしい。
HTTPレスポンスヘッダーにPermissions-Policyを追加
不要な機能を徹底的に「なし(none)」に制限する
add_header Permissions-Policy “geolocation=(), microphone=(), camera=(), payment=(), usb=(), display-capture=()”;
解説:
=()とすることで、そのサイト内(およびiframe内)のすべてのオリジンに対して機能を禁止している。- もし特定のドメイン(例えば決済用のサードパーティ製iframe)にのみ許可を与えたい場合は、
camera=(self "https://trusted-payment.com")のように記述する。
—
3. アプリケーション側での制御(PHP / Python)
インフラ層だけでなく、アプリケーション側でも動的に設定したいケースがあるだろう。その場合は、フレームワークのミドルウェア層で付与するのがベストプラクティスだ。
PHP (Laravel等のミドルウェア例)
// ミドルウェアでヘッダーを付与する
public function handle($request, Closure $next)
{
$response = $next($request);
// カメラ、マイク、ジオロケーションをすべて遮断
$response->headers->set(‘Permissions-Policy’, ‘geolocation=(), camera=(), microphone=()’);
return $response;
}
Python (Flask / FastAPI)
FastAPIでの実装例
@app.middleware(“http”)
async def add_security_headers(request, call_next):
response = await call_next(request)
# セキュリティリスクを最小化する設定
response.headers[“Permissions-Policy”] = “geolocation=(), camera=(), microphone=(), usb=()”
return response
—
4. 現場のシニアエンジニアからの忠告
Permissions Policyを導入する際、初心者が陥りがちな罠が2つある。
1. 「とりあえず全部許可()しておこう」という怠慢
- これでは意味がない。常に「最小権限の原則」に従い、空の括弧
()で全拒否し、必要なものだけを明示的に開放する姿勢を徹底すること。
2. サードパーティ製iframeの考慮漏れ
- 外部の広告タグやチャットボットがカメラやマイクを要求するケースがある。導入前にブラウザのデベロッパーツール(Networkタブ)を開き、どの機能がブロックされているかコンソールエラーを確認する「儀式」を怠らないこと。
最後に:セキュリティは「多層」で考える
Permissions Policyは、XSSを「修正」するものではなく、XSSが成功した後の「被害を食い止める」ための盾だ。
堅牢な開発とは、「脆弱性を生まない努力(入力チェック・出力エスケープ)」と「万が一の際に被害を局所化する努力(CSPやPermissions Policy)」の両輪で成り立つ。
今日からこのヘッダーを導入すれば、君たちのアプリケーションは、攻撃者にとって「非常にコストの高い、割に合わない標的」へと姿を変えるはずだ。技術は人を守るためにある。さあ、今すぐサーバーの設定ファイルを開いてくれ。
コメント