プロトタイプ汚染 - Prototype Pollution
JavaScript のプロトタイプチェーンを悪用し、オブジェクトのプロパティを改ざんする攻撃。npm パッケージ経由で発生しやすい。
概念図
攻撃シナリオ
ディープマージ関数を悪用した Prototype Pollution
bash
// 脆弱なディープマージ関数
function merge(target, source) {
for (const key in source) {
if (typeof source[key] === "object") {
target[key] = merge(target[key] || {}, source[key]);
} else {
target[key] = source[key];
}
}
return target;
}
// 攻撃ペイロード
merge({}, JSON.parse('{"__proto__":{"isAdmin":true}}'));
// すべてのオブジェクトに isAdmin=true が追加される
console.log({}.isAdmin); // trueURL パラメータ経由の攻撃と安全なオブジェクト生成
bash
// URL パラメータ経由の攻撃
// ?__proto__[isAdmin]=true
// qs ライブラリの古いバージョンなどで発生
// 安全な実装(Object.create(null) を使う)
const safeObj = Object.create(null);
safeObj.key = "value";
// → プロトタイプチェーンを持たないため汚染されない攻撃の仕組み
JavaScript のオブジェクトは __proto__ プロパティを通じてプロトタイプチェーンにアクセスできる。
オブジェクトのマージやクローン処理で __proto__ キーを適切にフィルタリングしていない場合、Object.prototype にプロパティを追加できてしまう。
汚染されたプロパティはアプリケーション内の全オブジェクトに影響するため、以下のような深刻な被害につながる:
- 認証バイパス(
isAdminプロパティの注入) - XSS の発生(テンプレートエンジンの動作を改ざん)
- DoS(アプリケーションのクラッシュ)
- リモートコード実行(サーバーサイド Node.js 環境で)
対策
__proto__キーのフィルタリング: マージ・クローン処理で__proto__,constructor,prototypeを除外するObject.create(null)の使用: プロトタイプチェーンを持たないオブジェクトを利用する- Map の使用: キーバリューストアには
Objectの代わりにMapを使う - Object.freeze:
Object.freeze(Object.prototype)でプロトタイプを凍結する(互換性に注意) - 依存パッケージの更新: lodash の
merge、jQuery のextend等は過去に脆弱性が報告されており、最新版に更新する
