午前I問題
JavaScriptのオブジェクト指向機構に関する記述として、適切なものはどれか。
ア)JavaScriptのオブジェクトはクラスベースの継承のみをサポートし、実行時にプロトタイプを変更することはできない。
イ)JavaScriptのオブジェクトはプロトタイプチェーンと呼ばれる仕組みでプロパティを継承しており、__proto__ などを介して共通の祖先である Object.prototype を書き換えると、その影響は当該オブジェクトを継承する全てのオブジェクトに及び得る。
ウ)Object.prototype はエンジンによって読み取り専用に固定されており、アプリケーションコードから変更することは一切不可能である。
エ)プロトタイプチェーンはJavaScriptのみに存在する概念であり、他言語のオブジェクト指向機構と比較することに意味はない。
午前I の解答・解説を見る
正解: イ
解説:
- ア)不正解。JavaScriptはプロトタイプベースの言語であり、実行時にプロトタイプを動的に変更できる。
- イ)正解。JavaScriptのオブジェクトはプロトタイプチェーンによってプロパティ・メソッドを継承する。
Object.prototypeは全てのオブジェクトの祖先にあたるため、これが汚染(改ざん)されるとアプリケーション全体に影響が及ぶ可能性がある。これが「プロトタイプ汚染」の技術的背景である。 - ウ)不正解。デフォルトでは書き換え可能であり、
Object.freeze(Object.prototype)等の対策を明示的に施さない限り変更できてしまう。 - エ)不正解。プロトタイプベースの継承はJavaScript以外の言語(例:Self、一部のLua実装)にも存在する概念である。
午前II問題
Node.jsアプリケーションにおける「プロトタイプ汚染(Prototype Pollution)」攻撃に関する記述のうち、最も適切なものはどれか。
ア)攻撃者は、SQLクエリのパラメータに __proto__ という文字列を挿入することで、データベースの権限昇格を直接引き起こす。
イ)攻撃者は、ユーザ入力をオブジェクトへ再帰的にマージ(deep merge)するライブラリ等に対して {"__proto__": {"isAdmin": true}} のようなJSONを送り込み、Object.prototype にプロパティを追加・上書きすることで、後続処理での認可判定バイパスやDoS、条件次第ではRCEを引き起こす。
ウ)プロトタイプ汚染は通信経路の暗号化強度に起因する脆弱性であり、TLS 1.3を導入することで根本的に解消される。
エ)プロトタイプ汚染はサーバのファイルシステム権限設定の不備によってのみ発生し、アプリケーションコードの実装とは無関係である。
午前II の解答・解説を見る
正解: イ
解説:
- ア)不正解。プロトタイプ汚染はSQLではなくJavaScriptのオブジェクト構造を対象とする攻撃であり、SQLインジェクションとは別の脆弱性である。
- イ)正解。安全でない再帰的マージ・クローン・プロパティ設定処理(
_.merge、JSON.parseの結果をそのままマージする自作関数等)が__proto__やconstructor.prototypeというキーを特別扱いせずに処理すると、Object.prototypeを汚染できる。汚染されたプロパティはアプリケーション内の全てのプレーンオブジェクトに継承されるため、認可フラグの上書きによる権限昇格や、テンプレートエンジン経由でのRCEにつながった実例が報告されている。 - ウ)不正解。TLSは通信路の暗号化であり、アプリケーションロジックの脆弱性であるプロトタイプ汚染とは無関係。
- エ)不正解。ファイルシステム権限とは無関係で、アプリケーションのオブジェクト操作ロジックに起因する。
午後問題
E社はNode.js(Express)で構築した設定管理APIを提供している。このAPIは、クライアントから送られたJSONをユーザ設定オブジェクトに再帰的にマージして保存する機能を持つ。セキュリティ診断で以下が判明した。
診断結果
- 設定マージ処理は自作の
deepMerge(target, source)関数で実装されており、sourceのキーを再帰的にtargetにコピーしているだけで、キー名に関する特別な処理を行っていない。 - 診断者が以下のリクエストボディを送信したところ、以降の全リクエストで、本来
falseであるべき管理者判定フラグがtrueとして扱われるようになった。
{
"theme": "dark",
"__proto__": {
"isAdmin": true
}
}
- アプリケーションの別モジュールでは、
user.isAdminを明示的に設定していないユーザオブジェクトに対してif (user.isAdmin) { ... }という判定を行っている箇所が複数存在した。
設問1
この脆弱性が発生した技術的なメカニズムを、「プロトタイプチェーン」という語を用いて80字以内で説明せよ。また、なぜ一度の攻撃で「以降の全リクエスト」に影響が及んだのか、その理由を述べよ。
設問1の解答・解説を見る
正解例:
- メカニズム:
deepMergeがキー名を検証せずに再帰処理を行うため、__proto__というキーが特別扱いされず、全オブジェクトの共通の祖先であるObject.prototypeにプロパティが追加され、プロトタイプチェーンを通じて他のオブジェクトにも継承されてしまう(77字)。 - 全リクエストに影響が及んだ理由:
Object.prototypeはNode.jsのプロセスが稼働している間、アプリケーション内の全てのプレーンオブジェクトで共有される単一のグローバルな存在であり、一度汚染されるとプロセスを再起動するまで影響が持続するため。
解説: プロトタイプ汚染の恐ろしさは、汚染対象が特定のリクエストやセッションに閉じたデータではなく、Node.jsプロセス全体で共有される Object.prototype である点にある。そのため一度の攻撃で、汚染後に生成される全てのオブジェクト(別ユーザのリクエストで生成されるものも含む)に影響が及ぶ、いわば「グローバルな状態改ざん」となる。
解説・採点基準(計15点):
| 採点項目 | キーワード | 配点 |
|---|---|---|
| メカニズムに「キー検証なし」「Object.prototype改ざん」への言及 | proto、検証なし、Object.prototype | 6点 |
| メカニズムに「プロトタイプチェーン」を用いた継承の説明 | プロトタイプチェーン、継承 | 4点 |
| 全リクエスト影響の理由に「プロセス全体で共有される単一の存在」への言及 | グローバル、プロセス共有、再起動まで持続 | 5点 |
設問2
この脆弱性を修正するための対策を、実装レベルで3つ挙げよ。また、認可判定ロジック側で採るべき恒久的な設計指針を1つ述べよ。
設問2の解答・解説を見る
正解例:
- 実装レベルの対策:
deepMerge内でキーが__proto__・constructor・prototypeである場合は処理をスキップ(拒否)する。Object.create(null)で生成したプロトタイプを持たないオブジェクトをマージ先に使用し、汚染の影響範囲を遮断する。- 信頼できる実装・監査済みの安全なマージライブラリ(プロトタイプ汚染対策済みのバージョン)を利用し、独自実装を避ける。
- 認可判定の設計指針:
user.isAdminの真偽判定のように重要なセキュリティ判定を行う値は、外部から到達可能な汎用オブジェクトのプロパティに直接依存させず、Object.hasOwn()で自身のプロパティであることを明示的に確認する、または専用のクラス・Mapなどプロトタイプ継承の影響を受けないデータ構造で管理する。
解説: 実装面では危険キーの拒否(ブロックリスト)が即効性のある対策だが、網羅性に限界があるため、Object.create(null) や Map の使用、あるいは Object.freeze(Object.prototype) の併用など多層的な防御が推奨される。認可のような重要なロジックは、汚染されうるプレーンオブジェクトのプロトタイプ継承に依存しない設計にすることが恒久対策となる。
解説・採点基準(計15点):
| 採点項目 | キーワード | 配点 |
|---|---|---|
危険キー(__proto__等)の拒否・フィルタリング | __proto__拒否、キーフィルタ | 4点 |
Object.create(null) またはMap等プロトタイプなし構造の利用 | Object.create(null)、Map | 4点 |
| 安全なライブラリ利用など追加対策 | 監査済みライブラリ、freeze | 3点 |
| 認可判定を汎用オブジェクトに依存させない設計指針 | hasOwn、専用クラス、Map管理 | 4点 |
重要キーワード
| 用語 | 説明 |
|---|---|
| プロトタイプ汚染(Prototype Pollution) | __proto__ 等を介して Object.prototype を改ざんし、アプリケーション全体のオブジェクト挙動に影響を与える攻撃 |
| プロトタイプチェーン | JavaScriptオブジェクトがプロパティを継承するために辿る参照の連鎖 |
| deepMerge(再帰的マージ) | オブジェクトを再帰的に結合する処理。キー検証がないとプロトタイプ汚染の温床になる |
| Object.create(null) | プロトタイプを持たないオブジェクトを生成し、汚染の影響を遮断する手法 |
危険キー(__proto__ / constructor / prototype) | プロトタイプ汚染で悪用される特殊なプロパティ名 |
| クロスサイトスクリプティング(XSS) | プロトタイプ汚染がテンプレートエンジン経由でXSSやRCEに発展する事例と関連する |
まとめ
- 午前I視点: JavaScriptがプロトタイプベースの継承モデルであり、
Object.prototypeが全オブジェクトの共通祖先であることを理解する - 午前II視点:
__proto__キーを利用した再帰的マージ処理の悪用によるObject.prototype改ざんのメカニズムと、権限昇格・DoS・RCEへの発展パターンを押さえる - 午後視点: 危険キーのフィルタリング、
Object.create(null)、安全なライブラリ利用という実装対策と、認可判定を汚染耐性のあるデータ構造で行う設計指針をセットで説明できるようにする