Hello there, ('ω')ノ
プロトタイプ汚染とは?
Prototype Pollution(プロトタイプ汚染) は、JavaScriptの「プロトタイプ継承」の仕組みを悪用して、攻撃者がグローバルオブジェクトに不正なプロパティを追加し、それを他のオブジェクトに「引き継がせる」脆弱性です。
簡単に言えば:
「すべてのオブジェクトに影響する設定ファイルを書き換えられてしまう危険なバグ」
なぜ危険なのか?
プロトタイプ汚染を使うと、攻撃者は以下のようなことが可能になります:
- 本来アクセスできない内部の設定(config)を書き換える
- サーバーサイドで意図しないコードを実行(Remote Code Execution)
- クライアントサイドでDOMベースのXSS(クロスサイトスクリプティング)
例:設定ファイル(config)を汚染する
let config = {} Object.assign(config, JSON.parse('{"__proto__": {"isAdmin": true}}')); console.log({}.isAdmin); // true
このように、空のオブジェクトでもisAdminプロパティを持つようになってしまいます。
脆弱性が生まれる原因
プロトタイプ汚染は主に次のようなケースで発生します:
- ユーザー入力(リクエストなど)を含むオブジェクトを「マージ(merge)」する処理がある
__proto__やconstructorといった特殊キーのフィルタリングを行っていない
典型的な危険コード
function merge(target, source) { for (let key in source) { if (typeof source[key] === 'object') { if (!target[key]) target[key] = {}; merge(target[key], source[key]); } else { target[key] = source[key]; } } }
この関数に以下のようなユーザー入力を渡すと…
{ "__proto__": { "isAdmin": true } }
Object.prototypeが書き換えられ、すべてのオブジェクトがisAdmin: trueを持つようになります。
なぜ __proto__ が危険なのか?
JavaScriptでは、オブジェクトの「親(プロトタイプ)」を指定するために __proto__ という特殊なプロパティがあります。これを書き換えると、そのオブジェクトが継承する内容すべてが変更される可能性があります。
つまり:
1カ所の汚染で、すべてのオブジェクトに影響が及ぶ!
攻撃のポイント・コツ
__proto__やconstructor,prototypeなどのキーを入力に含めるmergeやdeepAssignなどの関数が使われているコードを探すconfigやoptionsといったオブジェクトが再利用されている場所に注目- 予期せぬオブジェクトプロパティが参照される処理を探す
対策方法
キーのフィルタリング
__proto__,constructor,prototypeなどを入力から除外する安全なマージライブラリの使用 例:
lodashのmergeでは_.setや_.mergeWithで対策が可能オブジェクトのクローンを作ってから操作 直接マージせず、新しいオブジェクトに安全にコピーする
まとめ
| 項目 | 内容 |
|---|---|
| 脆弱性名 | Prototype Pollution(プロトタイプ汚染) |
| 危険度 | 高(他の脆弱性と組み合わせてRCEなど) |
| 主な原因 | マージ処理でのキー検証の欠如 |
| 攻撃の目的 | グローバルなオブジェクトのプロパティ汚染 |
| 対策 | キーのフィルタリング、安全なライブラリ使用 |
おわりに
プロトタイプ汚染は、一見些細なミスから重大なセキュリティ事故につながる厄介な脆弱性です。JavaScriptの内部動作を正しく理解し、ユーザー入力を過信せず、セキュリティ対策を徹底しましょう。
Best regards, (^^ゞ