あまり知られていないセキュリティ欠陥の一つにプロトタイプ汚染が挙げられます。2017年に研究者の間で攻撃経路として注目され、2018年初頭には実際の事例が確認されました。
プロトタイプ汚染を利用した攻撃に伴うリスクは何か、またその対策はどうすればよいか。本記事ではこれらの疑問に詳しく触れていきます。
プロトタイプ上書きの脆弱性により、不正な利用者が JavaScript 環境を狙えるようになります。既存の JavaScript で構築されたプロトタイプにプロパティを挿入することで、ハッキングを試みる攻撃です。
攻撃者は、基底オブジェクトの雛形を無効化または汚染する変数を注入でき、これがプロパティ注入と呼ばれる脆弱性につながります。この有害な現象は、継承関係にある複数のオブジェクトに影響します。ハッカーがオブジェクトの既定の属性を変更できれば、アプリのロジックまで改変され、DoS や遠隔コード実行 (RCE) などの被害が生じる可能性があります。
欧州コンピュータ製造者協会 (ECMA) は ECMAScript2015、第6版の要求事項を発表し、その中でプロトタイプ汚染の概念を盛り込みました。これにより統一された ECMAScript 標準が確立されました。
標準化された機能の一つに、オブジェクトの性質を認識するための __proto__ 属性があります。ECMAScript の全ての項目はこの性質を持ち、__proto__ 自体が項目の説明となっています。‘プロトタイプ’ という用語は、ECMAScript オブジェクト間で資産を共有する仕組みを示します。
プリミティブ型を除けば、ECMAScript に入力する全てはオブジェクトであり、これらは入れ子になり、互いにプロトタイプを継承できます。まさにその連鎖が生じるのです。
ハッカーが通常、新たな雛形を挿入することで __proto__ 属性を改ざんする場合、これを雛形改ざんと呼びます。全ての JavaScript 項目は __proto__ を有し、すべてのエンティティがプロトタイプを継承するため、新たなプロトタイプは自動的に連鎖の一部となります。
このように、攻撃者が既存の JavaScript オブジェクトに属性を注入し、DoS、悪質なコードによる遠隔コード実行、またはその他深刻な影響をもたらす例外を発生させる可能性があることが明らかになります。
任意の特性をプロトタイプに与えられるユーザー操作可能な入力は、プロトタイプ汚染の要因です。代表的なものは以下の通りです:
以下は、攻撃によって生成されたクエリ文字列が URL に挿入された例です:
https://vulnerable-website.com/?__proto__[evilProperty]=payload
クエリ文字列をキーと値の組に分解する際、URL パーサは __proto__ を単なる文字列と誤認する場合があります。しかし、これらの値とキーが既存のオブジェクトに属性として組み込まれると、どのような事態が起こるでしょうか。
ターゲットオブジェクトに __proto__ プロパティとその内部の evilProperty を追加することは単純に思えるかもしれません。
しかし、そうとは限りません。再帰的なマージ操作の任意の段階で、次のような文により evilProperty の値が割り当てられる可能性があります:
この代入時、JavaScript エンジンは __proto__ をプロトタイプのゲッターとして解釈します。その結果、意図したターゲットオブジェクトではなく、返された雛形オブジェクトに evilProperty が設定されます。同じキーのプロパティを持たない限り、ECMAScript の全項目が evilProperty を継承するようになります。ターゲットオブジェクトがデフォルトの Object.prototype を上書きしていても同様です。
多くの場合、「evilProperty」というプロパティを追加しても目立った影響はありません。しかし、攻撃者は同様の手法で、パッケージやインポートされたライブラリが依存するプロトタイプにプロパティを注入する可能性があります。
JSON.parse() メソッドは、JSON 文字列をユーザー操作可能なオブジェクトに変換するためによく用いられます。不思議なことに、JSON.parse() は、__proto__ などの特殊なキーも文字列として解釈します。これにより、有害なプロトタイプが拡散する新たな道が開かれます。
例えば、攻撃者からのウェブメッセージを通じて注入される可能性のある、以下の悪意ある JSON を考えてみましょう:
この JSON を JSON.parse() で解析すると、最終的な JavaScript オブジェクトには __proto__ というキーのプロパティが含まれます。
先述の URL 例のように、十分なキー検証を行わずに JSON.parse() で生成されたオブジェクトを既存のオブジェクトにマージすると、プロトタイプ汚染が発生する可能性があります。
JavaScript の移植性により、ウェブアプリのクライアント側とサーバ側の両方でプロトタイプ改ざんの脆弱性が発生する可能性があります。そのため、プロトタイプ攻撃による被害の深刻度や範囲はアプリごとに大きく異なります。以下にいくつかの例を示します:
プロトタイプ汚染攻撃により、攻撃者はクライアント側から対象ユーザーやアプリをホストするウェブサーバに対して DoS 攻撃を行えます。
プロトタイプ汚染により、属性が追加または変更され、予期せぬ動作が引き起こされることがあり、特定のロジックが正常に機能しなくなる恐れがあります。
プロトタイプ汚染の発生は、同一環境内の他のコンポーネント(ガジェット)を攻撃者が利用する足掛かりとなります。これにより、より巧妙な攻撃の実行や、更なるアクセス権の獲得、権限の引き上げが可能となります。
攻撃者は、例えば URL のようなクライアント側ロジックやアプリのレンダリングを行うコンストラクタにペイロードを埋め込むことで、プロパティ注入を悪用し始めます。例えば、URL パーサがターゲットとなるプロパティの関連性を確認せずに ECMAScript オブジェクトに属性を割り当てる場合があります。
また、クライアント側でのプロトタイプ汚染の悪用により、クロスサイトスクリプティング (XSS) など複数の攻撃が可能となります。ここでは、汚染されやすい属性に依存する仕組みが狙われます。オブジェクトがページの DOM と連携すると、攻撃者はクライアント側での ECMAScript 実行を誘発できます。
攻撃者がソフトウェア環境のツールを用いてオブジェクトの雛形の属性を変更する際、これをサーバ側での悪用と呼びます。悪意ある改変を受けた ECMAScript の実行は、クライアント側での攻撃よりも深刻な影響を及ぼす可能性があります。
プロトタイプ汚染の脆弱性の全容を把握するのは困難で、攻撃の詳細を明らかにするためにはアプリのロジックの解析が必要となる場合があります。それでも、サーバ側での悪用は RCE、SQL インジェクション (SQLi)、認証回避など深刻な結果につながる恐れがあります。
これは、ハッカーが悪意あるオブジェクトをパッケージのプロトタイプ連鎖に注入する際に発生する LiveScript の脆弱性です。予期せぬ動作や情報セキュリティの問題が引き起こされる恐れがあります。
以下は、JavaScript のプロトタイプ汚染を示す簡単なコード例です:
この例では、ハッカーが myObject の雛形に isAdmin プロパティを追加しています。myObject で isAdmin にアクセスすると true が返されます。この攻撃を防ぐため、ユーザー入力に対する検証とサニタイズは必ず行うべきです。
Wallarm は、プロトタイプ汚染の脆弱性を突く JavaScript 攻撃の阻止に寄与します。
API Security 基盤、WAAP、アプリ、そして cloud-native 環境で動作するサーバーレスワークロードは、セキュリティ専門家向けに開発された Wallarm の技術により確実に守られています。
Wallarm は、世界中の多くのプライバシー保護担当者や開発者に利用され、厳しい攻撃への迅速な対応、API 全体に及ぶ広範なセキュリティ、自動化されたイベント対応によって製品防衛を支えています。
ECMAScript 6 - www.w3schools.com
最新情報を購読