PHPのセキュリティ対策 続き

こちらの記事は以下の書籍を参考に執筆しました

[体系的に学ぶ 安全なWebアプリケーションの作り方 第2版［リフロー版］　脆弱性が生まれる原理と対策の実践](https://www.amazon.co.jp/%E4%BD%93%E7%B3%BB%E7%9A%84%E3%81%AB%E5%AD%A6%E3%81%B6-%E5%AE%89%E5%85%A8%E3%81%AAWeb%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E4%BD%9C%E3%82%8A%E6%96%B9-%E7%AC%AC2%E7%89%88%EF%BC%BB%E3%83%AA%E3%83%95%E3%83%AD%E3%83%BC%E7%89%88%EF%BC%BD-%E8%84%86%E5%BC%B1%E6%80%A7%E3%81%8C%E7%94%9F%E3%81%BE%E3%82%8C%E3%82%8B%E5%8E%9F%E7%90%86%E3%81%A8%E5%AF%BE%E7%AD%96%E3%81%AE%E5%AE%9F%E8%B7%B5-%E5%BE%B3%E4%B8%B8-%E6%B5%A9-ebook/dp/B07HHT54YR/ref=sr_1_2?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=%E4%BD%93%E7%B3%BB%E7%9A%84%E3%81%AB%E5%AD%A6%E3%81%B6%E3%81%82%E3%81%B7%E3%82%8A&qid=1595990262&s=digital-text&sr=1-2)


#クロスサイトリクエストフェージェリ
**クロスサイトリクエストフォージェリ(CSRF)**とは、サイトに攻撃用のスクリプトを仕込み、アクセスしてきたユーザーに意図しない操作を強制する攻撃のことを言います。

CSRF攻撃を受けると

- あるサービスに勝手に登録される
- 掲示板やブログに勝手に書き込みされる
- ショッピングサイトで商品を購入させられる

といった被害を受ける可能性があります。

##原因
例えば、通常サイトを装った攻撃者のサイトでは`<iframe>`タグにより別のスクリプトを読み込み、ページロードのタイミングでポストデータを送信する仕組みなど、あたかもユーザが自分で操作したかのようにデータを送信してしまいます。

##対策
セッションを利用し、入力側でランダムなトークンを生成し、処理側でセッションに保存したトークンとポストトークンデーが等しいかをチェックします。

このような手法のことを**ワンタイムトークン**といいます。

#パストラバーサル
パストラバーサルとは、本来想定していたパスをさかのぼって自由にファイルにアクセスされてしまう脆弱性のことです。

##原因
以下のコードは典型的なパストラバーサル脆弱性を含んでいます。

```php5:dowonload.php
<?php
$fl = $_GET['path'];
header('Content-Type: application/octet-stream');
header('Content-Type: attachment; filename="'.$fl.'"');

print file_get_content("./doc/{$fl}");
```
>出典：[体系的に学ぶ 安全なWebアプリケーションの作り方 第2版［リフロー版］　脆弱性が生まれる原理と対策の実践](https://www.amazon.co.jp/%E4%BD%93%E7%B3%BB%E7%9A%84%E3%81%AB%E5%AD%A6%E3%81%B6-%E5%AE%89%E5%85%A8%E3%81%AAWeb%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E4%BD%9C%E3%82%8A%E6%96%B9-%E7%AC%AC2%E7%89%88%EF%BC%BB%E3%83%AA%E3%83%95%E3%83%AD%E3%83%BC%E7%89%88%EF%BC%BD-%E8%84%86%E5%BC%B1%E6%80%A7%E3%81%8C%E7%94%9F%E3%81%BE%E3%82%8C%E3%82%8B%E5%8E%9F%E7%90%86%E3%81%A8%E5%AF%BE%E7%AD%96%E3%81%AE%E5%AE%9F%E8%B7%B5-%E5%BE%B3%E4%B8%B8-%E6%B5%A9-ebook/dp/B07HHT54YR/ref=sr_1_2?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=%E4%BD%93%E7%B3%BB%E7%9A%84%E3%81%AB%E5%AD%A6%E3%81%B6%E3%81%82%E3%81%B7%E3%82%8A&qid=1595990262&s=digital-text&sr=1-2)



例えば
`http://localhost/selfphp/chap11/download.php?path=../../../../apache/conf/httpd.conf`
のようなアドレスを指定すると`httpd.conf`を入手できてしまいます。

##対策
パストラバーサルを防ぐ一番の方法は、**リクエスト情報として直接にはファイルパスを受け渡ししないことです。**

処理内容によってはどうしてもパスを直接受け渡しせざるを得ない場合もあります。その場合はホワイトリストを作るなどしてファイル名をチェックします。
**ホワイトリスト**とは、操作を許可する対象のリストのことです。

```php5:dowonload.php
<?php
$fl = $_GET['path'];

//ここから追記文

$flag = false;//ホワイトリストにマッチするかを判定するフラグ
$dir = new DirectoryIterator('./doc/');
foreach ($dir as $file) {//①
  //クエリ情報pathと等しいファイルが存在する場合のみ フラグをture
    if ($file->isFile() && $file->getFileName() === $fl) {
        $fl=$file->getFileName();
        $flag=true;
        break;
    }
}
//フラグ変数がfalseである場合は不正な要求としてエラ表示
if(!$flag){die('不正な要求です。');}

//ここまで追記分

header('Content-Type: application/octet-stream');
header('Content-Type: attachment; filename="'.$fl.'"');

print file_get_content("./doc/{$fl}");

```
>出典：[体系的に学ぶ 安全なWebアプリケーションの作り方 第2版［リフロー版］　脆弱性が生まれる原理と対策の実践](https://www.amazon.co.jp/%E4%BD%93%E7%B3%BB%E7%9A%84%E3%81%AB%E5%AD%A6%E3%81%B6-%E5%AE%89%E5%85%A8%E3%81%AAWeb%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E4%BD%9C%E3%82%8A%E6%96%B9-%E7%AC%AC2%E7%89%88%EF%BC%BB%E3%83%AA%E3%83%95%E3%83%AD%E3%83%BC%E7%89%88%EF%BC%BD-%E8%84%86%E5%BC%B1%E6%80%A7%E3%81%8C%E7%94%9F%E3%81%BE%E3%82%8C%E3%82%8B%E5%8E%9F%E7%90%86%E3%81%A8%E5%AF%BE%E7%AD%96%E3%81%AE%E5%AE%9F%E8%B7%B5-%E5%BE%B3%E4%B8%B8-%E6%B5%A9-ebook/dp/B07HHT54YR/ref=sr_1_2?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=%E4%BD%93%E7%B3%BB%E7%9A%84%E3%81%AB%E5%AD%A6%E3%81%B6%E3%81%82%E3%81%B7%E3%82%8A&qid=1595990262&s=digital-text&sr=1-2)


①で`/doc`フォルダ配下を順に読み込んでいます。これがホワイトリストです。
ここではホワイトリストとクエリ情報pathの値が合致しているかをチェックしています。

#nullバイト攻撃
ホワイトリストの代わりに、以下のようなチェックでも良いのでは、と思うかもしれません。

`if(!preg_match('/\.txt$/',$fl){die('不正な要求です。');})`

ファイル名の語尾を`.txt`に限定することで、もしパスを遡られてもテキストファイルにしかアクセスできないようにしようということです。

しかしこれは本質的な対策にならないばかりでなく、拡張子を限定するという役にすら立ちません。

以下のようにアクセスするとどうでしょう。

`http://localhost/selfphp/chap11/download.php?path../../../../apache/conf/httpd.conf%00.txt`

`%00`は**nullバイト**を表す表現で、文字列の終端を示します。`preg_match`関数はバイナリセーフ(バイトデータを正しく処理できる)ため、クエリ情報pathの終端を正しく.txtとみなして処理を継続します。クエリ情報pathをテキストファイルとしてみなします。

しかしPHP5.3.3以前の`file_get_contents`関数では`%00`以降を無視して結果として`httpd.conf`と判断されます。

nullバイトを使用した攻撃を**nullバイト攻撃**といいます。
nullバイト攻撃は入力値検証で防ぐことができます。対策は後述します。

#メールヘッダインジェクション
メールヘッダにインジェクションしてスパスメール等を送信させる攻撃のことです。

##原因
以下、メールヘッダ・インジェクションのサンプルです。

```php5
mb_send_mail('wings@example.com', $_POST['subject'], $_POST['body'], 
  "From: {$_POST['from']}");
```
>出典：[体系的に学ぶ 安全なWebアプリケーションの作り方 第2版［リフロー版］　脆弱性が生まれる原理と対策の実践](https://www.amazon.co.jp/%E4%BD%93%E7%B3%BB%E7%9A%84%E3%81%AB%E5%AD%A6%E3%81%B6-%E5%AE%89%E5%85%A8%E3%81%AAWeb%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E4%BD%9C%E3%82%8A%E6%96%B9-%E7%AC%AC2%E7%89%88%EF%BC%BB%E3%83%AA%E3%83%95%E3%83%AD%E3%83%BC%E7%89%88%EF%BC%BD-%E8%84%86%E5%BC%B1%E6%80%A7%E3%81%8C%E7%94%9F%E3%81%BE%E3%82%8C%E3%82%8B%E5%8E%9F%E7%90%86%E3%81%A8%E5%AF%BE%E7%AD%96%E3%81%AE%E5%AE%9F%E8%B7%B5-%E5%BE%B3%E4%B8%B8-%E6%B5%A9-ebook/dp/B07HHT54YR/ref=sr_1_2?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=%E4%BD%93%E7%B3%BB%E7%9A%84%E3%81%AB%E5%AD%A6%E3%81%B6%E3%81%82%E3%81%B7%E3%82%8A&qid=1595990262&s=digital-text&sr=1-2)



問題は`From: {$_POST['from']}");`の部分です。
このポストデータformに対して以下のような値を引き渡すとどうでしょう。

```
wings@xmail.com
Bcc:yamada@example.com
```

`wings@xmail.com`と`Bcc:yamada@example.com`の間は改行(\n)されているので、改行文字以降もBccヘッダとして認識されてしまいます。

##対策
メールアドレスの妥当性を検証することで、不正なヘッダを防ぐことができます。

```php5
if (!preg_match('/^\w+([-+.\']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/i', $_POST['from'])) {
  die('不正なメールアドレスです。');
}
```
>出典：[体系的に学ぶ 安全なWebアプリケーションの作り方 第2版［リフロー版］　脆弱性が生まれる原理と対策の実践](https://www.amazon.co.jp/%E4%BD%93%E7%B3%BB%E7%9A%84%E3%81%AB%E5%AD%A6%E3%81%B6-%E5%AE%89%E5%85%A8%E3%81%AAWeb%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E4%BD%9C%E3%82%8A%E6%96%B9-%E7%AC%AC2%E7%89%88%EF%BC%BB%E3%83%AA%E3%83%95%E3%83%AD%E3%83%BC%E7%89%88%EF%BC%BD-%E8%84%86%E5%BC%B1%E6%80%A7%E3%81%8C%E7%94%9F%E3%81%BE%E3%82%8C%E3%82%8B%E5%8E%9F%E7%90%86%E3%81%A8%E5%AF%BE%E7%AD%96%E3%81%AE%E5%AE%9F%E8%B7%B5-%E5%BE%B3%E4%B8%B8-%E6%B5%A9-ebook/dp/B07HHT54YR/ref=sr_1_2?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=%E4%BD%93%E7%B3%BB%E7%9A%84%E3%81%AB%E5%AD%A6%E3%81%B6%E3%81%82%E3%81%B7%E3%82%8A&qid=1595990262&s=digital-text&sr=1-2)


上記のサンプルにより、ポストデータの内容が正しいアドレスであるかをチェックしています。
これにより先の改行を含んだ文字列は指定できなくなるので、有効な対策となります。

#その他の攻撃と対策

##セッションハイジャック
何らかの方法でセッションIDを乗っ取ることを言います。
これをやられると個人情報やなりすましの被害に繋がります。

安対策としてはセッション関連のパラメータに適切な値を設定し、ログイン直後などのライミングでセッションを再生成すること(session_regenerate_id関数)が大切です。
##ファイルアップロード攻撃
不正なファイル(.phpファイルなど)をアップロードすることで任意のスクリプトを実行可能にしてしまう攻撃のことを言います。

一番の対策はファイルアップロード先を公開フォルダの外に設定することです。
並行してファイルアップロード時にファイルの種類を制御する対策も行います。

##eval攻撃
eval関数は指定された文字列をPHPスクリプトとして実行できるための関数です。
ecal攻撃はこれを利用して不正なコードを引き渡す攻撃のことです。

`eval($_GET['script']);`

上記ではクレイ情報に指定した任意のPHPスクリプトを実行できてしまいます。
自由度が高いため、システムに直接かつ致命的な攻撃が可能となります。

対策はecal関数を利用しないこと、利用せざるを得ないときでもユーザーか等の入力値を直接実行するのは避けるべきです。

そもそもeval関数を利用しなければいけないケースは非常にまれなので、まずはeval関数以外の方法を模索することがベストです。

##インクルード攻撃
require_once命令等のインクルード命令に対して、不正なパスを引き渡す攻撃のことです。

`require_once $_GET['path'];`

上記では`http://www.example.com/hoge.php`のような値を引き渡すことで任意のスクリプトを実行できてしまいます。

対策は以下のような方法があります

#####1. allow_url_include パラメータをOffにする
php.iniのallow_url_includeをOnにすると、外部サイトからのスクリプトが読み込み可能になります。外部スクリプトのインクルードが必要なことは殆どないのでOffにしておきます。

#####2． インクルード命令の引数にユーザ入力を含めない
そういうことです。

---
入力値の検証は後ほど。