2019/06/04 『体系的に学ぶ安全なWebアプリケーションの作り方第2版 脆弱性が生まれる原理と対策の実践』応用講座 (徳丸本応用講座)


# 過日


![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/7ad4f07c-1abc-ecc7-372a-45719a9a3120.png)

https://www.eg-secure.co.jp/registration_for_security_lecture_2/
https://egss.connpass.com/event/129443/

なになに、徳丸本によるホワイトハッカー入門？
ちょっと面白そうだな、行ってみようかな？

![02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/23b94ea3-201f-9262-9862-52d723562b51.jpeg)

さよなら。



# 2019/06/04

![03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/b86bc030-1e2d-9036-fd2e-b8844569a912.jpeg)
![04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26088/5ce79fcf-dc20-6c55-2e1e-d89993ef4cb1.png)

はい。


6月3日に基礎講座、4日に応用講座があったのですが、さすがに二日はつらかったので応用講座だけ受けてきました。
受講者は20名弱。

以下は講義の概要です。
リンクなどは私が適当に補足しています。
撮影や資料転載は禁止だったので、文字だけです。


# 講義概要

## Webセキュリティの基礎

### 受動的攻撃と同一オリジンポリシー

能動的攻撃とは、攻撃者がサーバに対して直接攻撃する手法。SQLインジェクションなど。
受動的攻撃は、サーバを利用して、Webサイトの利用者への罠を仕掛ける攻撃。XSSなど。

受動的攻撃を防ぐ機能のひとつが、同一オリジンポリシー。
JavaScriptは、同一オリジンのデータしか読むことはできない。
同一オリジンとは、
・FQDNが同じ
・スキーム(http/https)が同じ
・ポート番号が同じ

iframeやimgなどで別サイトのデータを画面に表示することはできる。
ただし、JavaScriptからそれらの中身を見ることはできない。


### CORS

JSはサイト間をまたがるデータのやりとりができない。
そういうニーズが高まったためCORSが策定され、一定の仕様を満たしたリクエストであればクロスオリジンでデータをやりとりできるようになった。
仕様がくっそややこしいのは既存の仕様と互換性を保つためであって、よく考えられてる。

サイトAからサイトBにリクエストを飛ばした場合、
・昔はリクエスト自体飛ばなかった。
・今は、サイトBのCORS設定にかかわらずリクエスト自体は飛ぶ。レスポンスも返ってくる。
・サイトBがCORSを許可していれば、返ってきたデータが展開される。
・サイトBがCORSを許可していなければ、返ってきたデータは破棄される。わりと水際防衛なのである。


## ファイルアップロードにまつわる問題

ファイルを公開ディレクトリに置くと即死。

非公開ディレクトリにアップし、参照はダウンロードスクリプト経由で行うこと。

拡張子チェックは、Apacheでは"foo.php.png"のように、拡張子はpngだがPHPとして動かせるような設定ができる。
そのため単純に拡張子をチェックするだけでは駄目で、サーバ側でファイル命名も必要。

### ファイルダウンロード時の問題

`Content-Type`を間違っていた場合、わからないファイルを勝手にHTMLとして扱ってXSSが発生することがある。
さらに正しい`Content-Type`を指定しても、IEは`Content-Type`を無視して勝手にHTMLとして扱うことがある。
`X-Content-Type-Options:nosniff`も指定すべき。
ブラウザ内実行の必要がなく、ダウンロードするだけでいいなら`Content-Disposition:attachment`を指定するのもよい。

そもそもアダルト・違法コンテンツなども上げられる可能性があるから、最終的に目視チェックは必要。

### PDFのFormCalcによるコンテンツハイジャック

PDFのFormCalcはHTTPリクエストを投げることができる。
ブラウザのPDFプラグインでPDFを表示していた場合、このリクエストにはなんとブラウザのCookieが載る。
要するに、PDFをアップロードできる = JavaScriptをアップロードできる、と思っていい。
https://jvn.jp/ta/JVNTA94087669/

サーバ上でPDFを開ける時点で防ぎようがないので、`X-Download-Options`ヘッダでダウンロードを強制させる。
さらにembed等で開かれたらそれも無視されるので、ダウンロードスクリプトへのアクセスをPOST限定にする。

ということだったのだが、POST限定にすると画像を表示できなくなったりと副作用が大きい。
PDFをアップロード禁止にするのが早そう。


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

### evalインジェクション

そもそもevalを使う時点で危険。
使うにしても、パラメータを外部から与えない、
どうしても外部パラメータが必要であれば、英数字に限定する。

シリアライズ目的ならJSONを使う。


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

[OWASP2017](https://www.owasp.org/index.php/Japan)で8番目に上げられるほどになった。

外部パラメータを[unserialize](https://www.php.net/manual/ja/function.unserialize.php)する際、マジックメソッドやデストラクタなどにうまいこと引数を与えることでなんやかんやできる。
脆弱性の例示はPHPだったのだが、PHPではデシリアライズする時点で読み込まれているクラスしか攻撃対象にできないが、Javaであればクラスパスの通っているクラス全てが対象なのでより危険。

マジックメソッドとか動かないJSONにするのが一番の対策。
もしくは、ユーザから操作できないセッションなどに保存するのでもいい。

ここの[例示で使われた攻撃対象クラス](https://blog.tokumaru.org/2015/07/phpunserialize.html)は、かなりわざとらしいかんじだったので、もっとスマートな例を考えてみたいところ。


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

XMLには外部実体参照という機能がある。この機能自体は完全に仕様。

```xml
<!ELEMENT hello "こんにちは">
<!ELEMENT goodnight SYSTEM "goodnight.txt">

<foo>
  <bar>&hello;</bar> // "こんにちは"になる
  <baz>&goodnight;</baz> // "goodnight.txt"の中身になる
</foo>
```

XMLをアップロードできると、このSYSTEMのところに`/etc/hosts`とか、`https://internal.example.com`とか書けてしまう。

対策は色々
・JSONを使う。
・libxml2.9以上を使う。デフォルトで外部実体参照が禁止されている。
・XMLをPHPでパースしているのであれば[libxml_disable_entity_loader(true)](https://www.php.net/manual/ja/function.libxml-disable-entity-loader.php)する。
・Javaであれば[DTDを禁止](https://www.mbsd.jp/blog/20171130.html)する。



## WebAPI実装における脆弱性

ここは、主にサーバ側の不備で発生する問題。

### JSONとJSONPの概要

JSONはただのJavaScriptのオブジェクト(を拡張したもの)。
MIMEタイプは"application/json"。

JSONPは、JSONを関数で囲ったもの。
CORSができる前に、クロスオリジンでデータのやりとりを行うために考案された方法。

```html:サイトA
<script>
  function foo(data){
    // dataは{a:1, b:2}
  }
</script>

<script src="https://サイトB/bar.js">
```

```js:サイトBのbar.js
  foo({a:1, b:2});
```

サイトAからは、`bar.js`の中身を見ることはできない。
しかし、`bar.js`はfoo関数を呼んでいるため、サイトAのfoo関数が呼ばれ、引数に`{a:1, b:2}`が入ってくる。
これによって、サーバBからサーバAに任意のデータを渡すことができるようになった。
MIMEタイプは"application/javascript"。


### JSONエスケープの不備

出力のJSONを手動で作ってるとXSSできる。
フロント側はJSON.parse使え、で終わり。
サーバ側はjson_encode使え、で終わり。

### JSON直接閲覧によるXSS

JSONの`Content-Type`を正しく`application/json`にしていない場合、JSONファイルに直接アクセスすると、JSONとして正しかったとしてもブラウザではXSSになることがある。
JSONなのにHTMLとしてパースされてしまうせい。
正しい`Content-Type`を出せば、古いIE以外は問題ない。
念を入れて`<`や`>`などもエスケープするとさらによい。

```php
	$json = json_encode(['key'=>'<>&\'"'], JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT); // {"key":"\u003C\u003E\u0026\u0027\u0022"}
```

診断をやってきた経験から言って、意外と`Content-Type`が適当なことが多い。


### JSONPのコールバック関数名によるXSS

JSONPでは、呼び出す関数名が固定だと既に存在する関数と被ったりして困ることがあるから、呼び出し側で関数名を指定できることが多い。

```html:サイトA
<script src="https://サイトB/bar.js?callback=display_time">
```

レスポンスで関数名をそのまま返しているとXSSになる。

関数名は英数字のみのバリデーションを入れたらおわり。


## JavaScriptの問題

ここは、主にフロント側の不備で起こる問題。

対策は、外部パラメータを使うな、に尽きる。

### DOM Based XSS

#### innerHTML

外部パラメータをinnerHTMLに入れると死ぬ。
`<script>`とか書いてあればブラウザが止めてくれるが、`onerror`などで回避できるから意味なし。

外部パラメータはinnerHTMLではなくtextContentに入れる。

むしろ、どうしてもHTMLが必要なところ以外はテキストでよかろう。

#### document.write

外部パラメータをdocument.writeに入れると死ぬ。
こっちは`<script>`タグも動く。

これは回避方法がないので、がんばってエスケープするか、そもそもdocument.writeを使わないようにする。

#### XMLHttpRequestのURL未検証

外部パラメータをXMLHttpRequestの宛先URLに入れると死ぬ。
宛先を罠サイトに書き換えることができれば、(罠サイトは当然CORSをフルオープンにするから)任意のJavaScriptを実行できる。

対策にはURLを検証すると言われたのだが、そもそもリクエスト先URLは固定にするのが一番安全だろう。

#### jQueryセレクタの動的生成によるXSS

```js:古いjQuery
 $('#idname') // id="idmane"の要素を取得
 $('.classname') // class="classname"の要素を取得
 $('<p>hello</p>') // DOM要素を生成 ←
```

こんなの全く知らんかったわ。
[API一覧](https://api.jquery.com/)にも出てこないし、この情報何処にあるんだろう。

外部パラメータをセレクタに入れられる場合、タグを突っ込んでDOM要素を生成させ、onerrorなどのJSを実行できてしまうことがある。

対策には、セレクタを動的生成しない。
動的生成が必要であれば[find](https://api.jquery.com/find/)を使う。
もしくは単に最新版にアプデする。

#### javascriptスキームによるXSS

外部パラメータを`location.href`や`img src`などに入れると死ぬ。

対策には、スキームをhttpかhttpsに限定する、とあったが、そもそも外部パラメータを入れないほうがよいだろう。


# 質問コーナー

最初の1問を聞き逃した。

## Webアプリでデータの保存先を外部ストレージにしているが、追加の対策は必要か

ストレージ自体の設定が甘くて外部に漏れる事故が多発しているので、注意が必要。

## CORSじゃなくて、JSONPでないとできないことはあるか

たぶんない。
互換性維持以外の理由で、今からJSONPを使う意味はない。

## PDFは"application/octet-stream"にすれば安全？

application/octet-streamであれば、ブラウザのPDFプラグインではなく、ダウンロードしてからPDFビューアで開くから安全。

## evalインジェクションなどはブラックボックステストで見つけられるのか

あるかどうかわからないから、とりあえず攻撃してみるが、安定した診断は難しい。
デシリアライゼーションについては、リクエスト形式を見ればわかるので指摘する。

## Vueなど最近のフレームワークを使えばXSSはなくなる？

フレームワークが勝手にエスケープしてくれるから、素のJSを使うよりは安全だろう。
でも絶対なくなるとは言えない。

## PHPを使ってないけど、Webセキュリティ試験を受ける価値はある？

徳丸本はPHPメインだが、[Webセキュリティ試験](https://www.phpexam.jp/news/tokumarushiken/)は言語に依存しないから意味はあるだろう。
試験の仕様上コードを書くとかは難しく、あくまで知識を問うだけの試験になる。
でも知識が無いよりはあったほうがいいから、理解度がどれくらいかという参考になるだろう。
2019年内に開始予定で、問題はだいたいできてて、そろそろベータ試験を始めたい。


# 講義の感想

徳丸本から重要な部分を抜き出して、いらすとやで再構築した資料が配布され、それについて解説していくというスタイルの講義でした。
基本的に本筋は徳丸本の範囲から外れないため、本を読んでいればだいたい知ってる内容でした。
もちろん読んだだけではわからないってところもあるので、そこの解説があったのはありがたいですが。

本を書いた後に判明した新手法の話とか、この講座を受けた人にここだけの話、みたいなのはありませんでした。
また、主催のEGセキュアソリューションズは脆弱性診断のサービスを提供している会社なので、そこで見つけた・発生した実際の事例について紹介してくれたりすると嬉しかったのですが、そういう話もありませんでした。

話自体は面白く参考になったのでまあよかったのですが、安くない金額を払っているのだから、そのような付加価値みたいなのもほしかったところです。
まあ、著者自ら解説してくれるというのが最大の付加価値かもしれませんが。


# おみやげ

受講証明書と、『体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践　第2版』をもらいました。
もちろん私物でも持っているので2冊になりました。

そういえば直筆サイン入り初版本がどこかにあったようなないような。


# その他

10年前は福岡のコンビニでバイトをしていたのですが、受講者に当時のバイトの同僚がいました。
どんな偶然だよ。
こんなの、なろうですら展開適当すぎって叩かれるわ。