---
# System prepended metadata

title: 4.14 構造化データの読み込みにまつわる問題

---

# 4.14 構造化データの読み込みにまつわる問題

安全なウェブアプリケーションの作り方の勉強会資料です。
今回の勉強会では、以下2点を扱います。
* 4.14.2 安全でないデシリアライゼーション
* 4.14.3 XML外部実体参照(XXE)


## 4.14.2 安全でないデシリアライゼーション


### 概要

* 転送・保存する目的で、データをバイト列に変換することをシリアライズという。
* シリアライズされたバイト列データをもとの形式に変換することをデシリアライズという
* アプリケーションが、シリアライズされた悪意あるデータを受け取るとき、任意のコードが実行されるおそれがある(オブジェクトインジェクション)

![シリアライゼーション](https://i.imgur.com/rGkQgom.png)
(引用:[徳丸浩の日記](https://blog.tokumaru.org/2017/09/introduction-to-object-injection.html))


### 攻撃手法と影響

#### 脆弱なアプリケーションの説明

「好きな色」を`Cookie`に保存する。(シリアライズ)
別ページで`Cookie`を読み取り、表示させる。（デシリアライズ）


1. `/4e/4e-10.php` にリクエスト
2. 「好きな色」(array)をシリアライズ
3. `Cookie`にシリアライズしたデータをセット
4. `/4e/4e-11.php` にリクエスト
5. ログ出力(`/4e/4e-12.php` )
6. `Cookie`を読み取り、デシリアライズ
7. 画面に「好きな色」を表示

```sequence
Client->Server: 1./4e/4e-10.php
Note right of Server: 2.Serialize
Server->Client: 3.slialize data を Cookieにセット
Note left of Client: Cookie
Client->Server: 4./4e/4e-11.php
Note left of Server: Cookie
Note right of Server: 5.Logging
Note right of Server: 6.Deserialize
Server->Client: 7.「好きな色」を表示
```
#### 攻撃手法の説明

Loggerクラスに対して攻撃する。
操作はテキスト`PP354-357`参照。

### 脆弱性が生まれる原因

P358に下記コードの攻撃シナリオの説明あり。
ハイライトした箇所が攻撃に利用されている。

1. `/var/www/html/xinfo.php`を`$path`としている
2. ログに'<?php phpinfo(); ?>'が書き込まれる
3. http://example.jp/xinfo.php にアクセスされると、実行される

<summary>/4a/4e-012.php</summary>

```diff=
<?php
class Logger {
  const LOGDIR = '/tmp/';  // ログ出力ディレクトリ
  private $filename = '';  // ログファイル名
  private $log = '';       // ログバッファ

  public function __construct($filename) {
    $this->filename = basename($filename); // ファイル名
    $this->log = '';             // ログバッファ
  }

// デストラクタではバッファの中身をファイルに書き出し
  public function __destruct() {
+    $path = self::LOGDIR . $this->filename;  // ファイル名の組み立て
// var_dump($path);
+    $fp = fopen($path, 'a');
    if ($fp === false) {
      die('Logger: ファイルがオープンできません' . htmlspecialchars($path));
    }
    if (! flock($fp, LOCK_EX)) {   // 排他ロックする
      die('Logger: ファイルのロックに失敗しました');
    }
+    fwrite($fp, $this->log); // ログの書き出し
    fflush($fp);             // フラッシュしてからロック解除
    flock($fp, LOCK_UN);
    fclose($fp);
  }

  public function add($log) {  // ログ出力
    $this->log .= $log;        // バッファに追加するだけ
  }
}
```


### 対策

* シリアライズ形式ではなくJSON形式によりデータを受け渡す
* クッキーやhiddenパラメータではなく、セッション変数など書き換えできない形でシリアライズ形式のデータを渡す
* HMACなどの改ざん検知の仕組みをどうにゅうしてデータが改ざんされていないことを確認する

#### シリアライズ形式ではなくJSON形式によりデータを受け渡す
---

JSONにすると安全な理由は、下記のブログ参照
https://blog.ohgaki.net/json-escape

<summary>/4a/4e-010a.php</summary>

```diff=
<?php
  $colors = array('red', 'green', 'blue');
- setcookie('COLORS', serialize($colors));
+ setcookie('COLORS', json_encode($colors));
  echo "クッキーをセットしました";
```

<summary>/4a/4e-011a.php</summary>

```diff=
<?php
  require '4e-012.php';
- $colors = unserialize($_COOKIE['COLORS']);
+ $colors = json_decode($_COOKIE['COLORS']);
//var_dump($colors);
  echo "好きな色は ";
  foreach ($colors as $color) {
    echo htmlspecialchars($color, ENT_COMPAT, 'UTF-8'), ' '; 
  }
  echo "です";
```

#### HMACでシリアライズした場合
---

鍵を設定し、公開キーをCookieに付与する。
デシリアライズの前に、改ざん検知を行う。
※php書いたことないので、間違えていましたら指摘お願い致します。
[参考](https://hackmd.io/0at41u4kScOrgXy1ChyMiQ?view)

鍵を生成する際に、`salt`という乱数を付与する。
これにより、レインボーテーブルによって割り出されづらくなる。

<summary>シリアライズ</summary>

```diff=
<?php
+ $secret_key = "random_bytes()で生成された強い鍵";
+ $salt = "random_bytes()で生成された強いsalt";

  $colors = array('red', 'green', 'blue');
+ // 送信するデータとその鍵の生成
+ $derived_key = bin2hex(hash_hkdf('SHA2-256', $secret_key, 0, serialize($colors), $salt));

  setcookie('COLORS', serialize($colors));
+ setcookie('DERIVED_KEY', $derived_key);
+ setcookie('SALT', $salt);
  echo "クッキーをセットしました";
```
<summary>デシリアライズ</summary>

```diff=
<?php
+ $secret_key = "random_bytes()で生成された強い鍵"; // 同じ鍵！
 
+ // 送信されて来たデータを使い、送信時の鍵導出と同じ手順で鍵を導出
+ $sent_key = bin2hex(hash_hkdf('SHA2-256', $secret_key, 0, $_COOKIE['COLORS'], $_COOKIE['SALT']));
 
+ // 再導出した鍵と送られてきた導出鍵を比較
+ if (hash_equals($sent_key, $_COOKIE['DERIVED_KEY'] !== true) {
+   die('攻撃を検出しました。処理を中止します。');
+ }
  require '4e-012.php';
  $colors = unserialize($_COOKIE['COLORS']);
//var_dump($colors);
  echo "好きな色は ";
  foreach ($colors as $color) {
    echo htmlspecialchars($color, ENT_COMPAT, 'UTF-8'), ' '; 
  }
  echo "です";
```

### 安全でないデシリアライゼーション まとめ

| 項目 | 内容 |
| -------- | -------- |
|   発生箇所   | 外部からの値をデシリアライズ処理しているページ     |
|   影響を受けるページ   | すべてのページが影響を受ける     |
|   影響の種類   | 情報漏えい、サイト改ざん、他サイトへの攻撃（踏み台）、暗号通貨の採掘（マイニング）     |
|   影響度合い   | 大     |
|   利用者の関与度合い   | 不要     |
|   対策   | [いずれかを実施](https://hackmd.io/d6kI6DZTTRiagZ7fnE854g?view#%E5%AF%BE%E7%AD%96)     |

## 4.14.3 XML外部実体参照(XXE)

### 概要

* XMLには、外部ファイルを取り込むことができる機能がある(外部実体参照)
* 外部実体参照によってWebサーバ内のファイルを不正に読み取られる可能性がある

### 攻撃手法と影響

テキスト見ながら実演します

### 脆弱性が生まれる原因

XMLの外部実体参照はもともとの機能である。
XXEは上記機能を悪用しているため、コーディング上にバグがあるわけではない。

### 対策(php)

* XMLの代わりにJSONを用いる
* libxml2のバージョン2.9以降を用いる
* libxml_disable_entity_loader(true)を呼び出す

以上！