インジェクション - XSS
XSSとしても知られるクロスサイト・スクリプティングは、インジェクション脆弱性のもう1つのタイプで、攻撃者が制御するスクリプトを他のユーザーのブラウザで評価させるものです。XSSは、HTML/JavaScriptインジェクションの脆弱性とも考えられます。
XSS脆弱性の影響は、脆弱性が存在するコンテキストに大きく依存します。スクリプトが実行されたページから情報を引き出すことができるものから、ページの状態を編集してページ上の被害者としてアクションを実行するものまで様々です。
遭遇する可能性のあるXSSのタイプを見てみましょう。
XSSタイプ
XSSを区別するために、いくつかのバケツに分けることができる。XSSは、ペイロードがどのように配信されるのか、また、どこから侵入するのかによって分類されます。
ペイロード配信ベクトル(保存 vs 反射)
攻撃者がXSSペイロードを配信する方法は2つあります:
- 保存型XSS:例えばデータベースに保存されたユーザー制御のデータを介して、他のユーザーにデータを表示する。
- 反射型XSS:ユーザーによってブラウズされたURL/クエリー文字列を通して渡される、ユーザー提供のペイロードを経由する。
重要な違いは、Reflected XSSは通常ユーザーとのインタラクションに依存し、悪意のあるペイロードを含むリンクを開いたユーザーにのみ影響を与えるということです。しかし、Stored XSSは、ペイロードをレンダリングするいくつかのページを開くだけで、1人以上のユーザーに対して実行することができます。
ペイロードの位置(DOM対非DOM)
ペイロードが注入される場所によって、脆弱性を「DOM」脆弱性と分類するかどうかが決まる。これは、ペイロードがレンダリングされる場所を区別することを意味します:
- 非DOM XSS:ペイロードがHTMLの内部(タグや属性の内部)でレンダリングされる。
- DOM XSS: The payload is rendered inside JavaScript, like a `<script>` tag, or an event handler such as `onclick=""`
XSS - 防御のためのプリミティブ
このセクションでは、XSSに対する防御の基礎となるプリミティブの原則について見ていきます。この基本を理解することは不可欠ですが、実際にはXSSに対する防御の99%はテンプレートライブラリに頼るべきです。
ブラウザで実行されるマークアップやコードにレンダリングされるテンプレートを書くとき、XSSから保護する鍵は*エンコーディング*です。この文脈でのエンコードとは、文字列を受け取り、インタープリターが特定の方法で処理する形式に変更することを意味します。
しかし、使用するエンコーディングのタイプは、データが使用される場所やコンテキストによって異なる。
- Inside a tag, like `<div>User input here</div>`: **HTML Encoding**
- Inside an attribute, like `<input placeholder="User input here"></input>`: **Attribute Encoding**
- Inside Javascript, like `<script>x = "User input here";</script>`: **JavaScript Encoding**
フレームワークの中には、エンコーディングを防御の主要な手段とはせず、代わりにサニタイズを利用して、危険な可能性のあるコンテンツから値を取り除くものもある。これは、多くのエッジケースを考慮する必要があり、より複雑なプロセスです。独自のサニタイズ・ルーチンを実装することは推奨されません。
例
実際にどのようなものなのか、さまざまな言語の例を見てみよう。
C# - 不安定:レイザー
IHtmlContent` オブジェクトの先頭に `@` が付いている場合、その値はエンコードされずに直接テンプレートに配置されます。
<!--- UNSAFE: The htmlSnippet will get interpreted without any escaping --->
@Html.Raw(htmlSnippet)
C# - セキュア:レイザー
デフォルトでは、`@` を先頭に持つ `string` は Razor テンプレートで HTML エスケープされます。
<!--- SAFE: The htmlSnippet will get HTML escaped --->
@htmlSnippet
Java - 安全:JSP
c:out`を使用する場合、デフォルトではXMLエスケープが使用されます(`escapeXml`プロパティで変更可能)。
<div><c:out value="<%= author %>" /></div>
Java - Secure: (fnxml)
上記と同様に、`fn:escapeXml`を直接呼び出すこともできます。これもHTMLコンテキストでのみ保護されます。
<div>${fn:escapeXml(author)}</div>
Javascript - 安全ではありません:Angular innerHtml
innerHTML`プロパティを指定することで、その名の通り、出力エンコーディングを無効にすることによるXSSのリスクにさらされることになります。
<!--- UNSAFE: The htmlSnippet will get interpreted without any encoding --->
<p [innerHTML]="htmlSnippet"></p>
Javascript - Secure:Angular補間
Angularの二重中括弧(`{{`と`}}`)を使ったテキストの補間は、その出力をHTMLエスケープし、XSSから保護します。
<!--- SAFE: The htmlSnippet will get encoded and then interpreted --->
<p>{{htmlSnippet}}</p>
Javascript - 安全ではありません:React dangerousInnerHtml
dangerouslySetInnerHTML`プロパティを指定することで、その名の通り、出力エンコーディングを無効にすることによるXSSのリスクにさらされることになります。
<!--- UNSAFE: As the name suggests, the dangerouslySetInnerHTML attribute is dangerous as it does not escape the output --->
<div dangerouslySetInnerHTML={{ __html: htmlSnippet }} />;
Javascript - Secure:リアクト補間
Reactの中括弧(`{`と`}`)を使ったテキストの補間は、その出力をHTMLエスケープし、XSSから保護します。
<!--- SAFE: The htmlSnippet will get encoded and then interpreted --->
<div>{htmlSnippet}</div>
Python - 安全ではありません:Django
Django テンプレートで `safe` フィルタを使うと、出力の自動エスケーピングが無効 になり、XSS から保護されません。
<!--- UNSAFE: The htmlSnippet will not get HTML encoded --->
<div>{{ htmlSnippet | safe }}</div>
Python - セキュア:Django
Django の二重中括弧 (`{{` と `}}`) を使ったテキストの補間は、その出力を HTML エスケープして XSS から保護します。
<!--- SAFE: The htmlSnippet will HTML encoded --->
<div>{{ name }}</div>