【テクニカル・上級編】Trusted Types APIによるDOMベースXSSの根本的防御 – アプリケーションセキュリティ & 安全な開発防御ガイド

DOM-based XSSの終焉:Trusted Typesによる「実行」の再定義

昨今のWebアプリケーションにおいて、SQLインジェクションはWAFやORMの普及により「過去の遺物」に近い扱いを受けつつある。しかし、DOM-based XSSだけは依然としてフロントエンドの深淵に潜み、開発者が意図せぬ「実行フローの分岐」を許し続けている。

innerHTMLやdocument.writeといった危険なシンク(Sink)は、ブラウザにとって「文字列をコードとして解釈せよ」という直球の命令だ。これをフロントエンドのバリデーションだけで防ごうとするのは、海水の侵入をザルで防ごうとするようなものだ。

今回は、この「非安全なデータフロー」を根本から断ち切るための次世代の防衛線、Trusted Types APIについて、アーキテクトの視点から深掘りする。

—

なぜ「サニタイズ」では不十分なのか

多くの開発者は、入力値に対してDOMPurifyなどを使い、サニタイズを行うことで安心を得ようとする。だが、これは「防御的コーディング」の域を出ない。

セキュリティの本質は「信頼できないデータが、実行可能な関数に到達するパスそのものを物理的に遮断すること」にある。

Trusted Typesは、ブラウザの実行エンジン自体を書き換えるアプローチだ。これを有効にすると、innerHTMLなどのシンクは、文字列を直接受け取ることを拒否し、「TrustedHTMLという特別な型」のみを許可するように強制される。これにより、攻撃者がいくら巧妙なペイロードを混入させても、型変換のプロセスを通らない限り、ブラウザはその文字列をHTMLとしてパースすることすら拒絶する。

Trusted Typesの実装戦略:防御のパイプライン

Trusted Typesの実装は、単なるコードの書き換えではない。これはフロントエンドにおける「コンパイル時の型安全を、実行時のメモリ安全にまで拡張する」作業だ。

1. ポリシーの定義

まず、アプリケーション全体で許容される「安全な変換」を定義するポリシーを作成する。

// セキュリティポリシーの定義: 信頼できる変換のみを許可する
if (window.trustedTypes && trustedTypes.createPolicy) {
const policy = trustedTypes.createPolicy(‘myAppPolicy’, {
// createHTMLメソッドを通る文字列のみがinnerHTMLへの代入を許される
createHTML: (input) => {
// ここでDOMPurify等を用いた厳格なサニタイズを強制する
// これを通過しないものは実行されない
return DOMPurify.sanitize(input, { RETURN_TRUSTED_TYPE: true });
}
});
}

2. CSPによる強制(Enforcement)

コードを書くだけでは不十分だ。攻撃者がポリシーを回避する可能性を排除するため、HTTPレスポンスヘッダーで「強制モード」を有効にする。

Content-Security-Policy: require-trusted-types-for ‘script’; trusted-types myAppPolicy;

このヘッダーを設定した瞬間、myAppPolicyを経由しない全てのinnerHTMLへの代入はブラウザのコンソールでエラーとなり、実行が阻止される。これは、レガシーなコードが混在する巨大なフロントエンドにおいて、「何が危険なパスを通っているか」を可視化する最強のデバッグツールにもなる。

—

アーキテクトが直面する「移行」の現実

理論は完璧だが、既存の巨大なプロダクトにこれを導入するのは容易ではない。段階的な移行のための戦略を提示する。

1. Report-onlyモードの活用:
Content-Security-Policy-Report-Onlyを使用して、まずは破壊的な変更を加えずに違反ログを収集せよ。どのコンポーネントが危険なシンクに直接触れているか、全容を把握するのが先決だ。
2. サードパーティライブラリの罠:
多くの場合、脆弱性は自作コードではなく、古いUIライブラリやトラッキング用スクリプトの中に潜んでいる。これらに対しては、ポリシー側で「特定のドメインからのスクリプトのみ例外を認める」といった調整が必要になるが、これは最後の手段とすべきだ。
3. 生成AIによるコード補完へのガードレイル:
現在、GitHub Copilot等のAIが生成するコードは、往々にしてinnerHTMLを安易に推奨する。Trusted Typesを有効にしておくことで、AIが生成した「脆弱なコード」をIDE上だけでなく、ブラウザのランタイムレベルで即座に検知・棄却できる。これはまさに、AI開発時代における必須の「ガードレイル」だ。

—

結びに:境界線としての「型」

私が長年インシデントハンドリングの現場で見てきたのは、どれだけ優秀なエンジニアでも、忙殺されると必ず「サニタイズ漏れ」という初歩的なミスを犯すという現実だ。

人間はミスをする。しかし、ブラウザのエンジンはミスをしない。

Trusted Typesは、セキュリティの責任を「エンジニアの注意深さ」から「APIの制約」へとシフトさせる。これは、脆弱性(CVE)を個別のパッチで塞ぐという自転車操業から脱却し、「そもそも脆弱性が入り込む余地のない構造を作る」というセキュリティアーキテクトの理想形への一歩だ。

モダンなWeb開発において、innerHTMLを直打ちすることは、もはやプロのエンジニアが取るべき手段ではない。Trusted Typesという強固な防壁を構築し、ブラウザの実行権限を我々の管理下に置くべき時が来ている。

コメント

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