
インジェクション-XSS
XSSとも呼ばれるクロスサイトスクリプティングは、攻撃者が制御するスクリプトを他のユーザーのブラウザで評価する原因となる別のタイプのインジェクション脆弱性です。XSS は HTML/JavaScript インジェクションの脆弱性と見なすこともできます。
XSS 脆弱性の影響は、脆弱性が存在する状況に大きく依存します。その範囲は、スクリプトが実行されているページから情報を抽出できることや、ページの状態を編集して被害者としてページ上でアクションを実行できることまで多岐にわたります。
どのような種類の XSS に出くわすか見てみましょう。
XSS タイプ
XSS は区別しやすいようにいくつかのバケットに分割できます。ペイロードの配信方法とエントリポイントの場所によって分類されます。
ペイロード配信ベクトル (保存対反映)
攻撃者が XSS ペイロードを配信する方法は次の 2 つです。
- 保存された XSS: たとえば、データが他のユーザーにレンダリングされるデータベースなどに保存されているユーザー制御データを介して
- リフレクションされた XSS: ユーザーが参照する URL/クエリ文字列を介して渡されるユーザー提供のペイロードを介して
重要な違いは、Reflected XSSは通常、ユーザーの操作に依存し、悪意のあるペイロードでリンクを開いたユーザーにのみ影響するということです。ただし、Stored XSS は、ペイロードをレンダリングするページを開くだけで 1 人以上のユーザーに対して実行できます。
ペイロードの場所 (DOM と DOM 以外の場所)
ペイロードが注入される場所によって、脆弱性を「DOM」脆弱性として分類するかどうかが決まります。これは、ペイロードがレンダリングされる場所の違いを示しています。
- ノンドム XSS: ペイロードは、タグ内にあるか属性内にあるかにかかわらず、HTML 内でレンダリングされます
- ドム XSS: ペイロードは、`` <script>タグのように JavaScript の内部にレンダリングされるか、`onclick= "" `のようなイベントハンドラでレンダリングされます
XSS-ディフェンスプリミティブ
このセクションでは、XSS に対する防御の基礎となるプリミティブの原則を見ていきます。この基本を理解することは不可欠ですが、実際には、XSS に対する 99% の保護はテンプレートライブラリに頼るべきです。
ブラウザで実行されているマークアップやコードにレンダリングされるテンプレートを記述する場合、XSS からの保護の鍵は*encoding* です。ここでいうエンコーディングとは、一連の文字を取り出して、それをインタープリターが特定の方法で処理する形式に変更することを指します。
ただし、使用するエンコーディングのタイプは、データが使用される場所またはコンテキストによって異なります。
- タグ内 (例:<div>ユーザー入力はこちら</div> `): **HTML エンコーディング**
- `<input placeholder="User input here"></input>` のような属性内:**属性エンコーディング**
- Javascript の内部では `<script>x =「ユーザ入力はこちら」;</script>`: **JavaScript エンコーディング**
フレームワークによっては、主な防御手段としてのエンコーディングを控え、代わりにサニタイズを利用して危険なコンテンツから値を削除します。これははるかに複雑なプロセスであり、考慮すべきエッジケースも多くあります。独自のサニタイズルーチンを実装することはお勧めしません。
例
さまざまな言語の例をいくつか見て、実際にどのように見えるか見てみましょう。
C#-安全でない:かみそり
`IHTMLContent` オブジェクトの前に `@` が付いている場合、値はエンコーディングなしで直接テンプレートに配置されます。
<!---UNSAFE: The htmlSnippet will get interpreted without any escaping--->
@Html .Raw (HTML スニペット)
C#-セキュア:カミソリ
デフォルトでは、先頭に `@`が付いている `string`は、RazorテンプレートでエスケープされたHTMLです。
<!---SAFE: The htmlSnippet will get HTML escaped--->
@htmlSnippet
ジャワ-セキュア:JSP
`c: out` を使用すると、デフォルトで XML エスケープ (`EscapeXml` プロパティで変更できます) になり、HTML コンテキストでは XSS から保護されますが、他のコンテキストでは保護されません。
<div><c:out value="<%= author %>" /></div>
ジャワ-セキュア:(fnxml)
上記と同様に、`fn: EscapeXml` を直接呼び出すこともできます。これにより、与えられた入力が XML エスケープされます。また、この方法では HTML コンテキストでのみ保護されます。
<div>$ {fn: エスケープXML (作成者)}</div>
Javascript-安全でない:アンギュラーインナーHTML
`innerHTML`プロパティを指定すると、その名の通り、出力エンコーディングが無効になるため、XSSのリスクにさらされることになります。
<!---UNSAFE: The htmlSnippet will get interpreted without any encoding--->
<p [innerHTML] ="htmlSnippet"></p>
ジャバスクリプト-セキュア:角度補間済み
Angularの二重中括弧 (`{{` と `}}`) を使ってテキストを補間すると、HTMLがその出力をエスケープし、XSSから保護します。
<!---SAFE: The htmlSnippet will get encoded and then interpreted--->
<p>{{HTML スニペット}}</p>
Javascript-安全でない:危険な内側のHTMLに反応する
`DangerouslySetInnerHTML` プロパティを指定すると、その名のとおり、出力エンコーディングが無効になるため、XSS が発生するリスクにさらされることになります。
<!---UNSAFE: As the name suggests, the dangerouslySetInnerHTML attribute is dangerous as it does not escape the output--->
<div dangerouslySetInnerHTML= {{__html: htmlSnippet}} />;
Javascript-セキュア:リアクト補間済み
React が中括弧 (`{` と `}`) を使ってテキストを補間すると、HTML はその出力をエスケープし、XSS から保護します。
<!---SAFE: The htmlSnippet will get encoded and then interpreted--->
<div>{HTML スニペット}</div>
Python-安全でない:ジャンゴ
Djangoテンプレートで「safe」フィルターを使用すると、出力の自動エスケープが無効になり、XSSから保護されなくなります。
<!---UNSAFE: The htmlSnippet will not get HTML encoded--->
<div>{{HTML スニペット | 安全}}</div>
パイソン-セキュア:ジャンゴ
Django では、二重中括弧 (`{{` と `}}`) を使用してテキストを補間すると、HTML が出力からエスケープされ、XSS から保護されます。
<!---SAFE: The htmlSnippet will HTML encoded--->
<div>{{名前}}</div>