PHP - WEB - 15. ドキュメントルートの指定

引き続きWebアプリケーションのセキュリティについて学習していきましょう。ここではWebサーバのドキュメントルートやコンテンツの公開範囲について考えます。

ドキュメントルート

ドキュメントルートとは、Webサーバ上で公開する基点となるディレクトリのことです。ドキュメントルートに指定したディレクトリの中にあるディレクトリやファイルは、Webブラウザから直接アクセスすることができるようになっています。そのためドキュメントルート下に、機密情報を扱うような重要なファイルを配置してしまうと情報漏えいのリスクが生まれます。

PHPプログラムの開発(ドキュメントルートの指定)

ここではさきほどのチャットプログラム( chat.php )を例にドキュメントルートの指定について考えてみましょう。ビルトインWebサーバを起動している状態で、以下のURLにアクセスするとチャット画面が表示されます。

http://localhost:8000/chat.php

このとき chat.php と同じディレクトリ上に chat.txt ファイルを配置しているので、アドレスバーから以下のようにURLを入力すると直接 chat.txt ファイルにアクセスできてしまいます。

http://localhost:8000/chat.txt

今回のようなチャットのメッセージが表示されるだけであれば問題ないかもしれませんが、個人情報を扱うような重要なファイルにアクセスされてしまうと被害は大きくなってしまいます。

このよう問題を防ぐために、データを扱うファイルはドキュメントルート下に配置しないようにします。ここでは以下に示すディレクトリ構成に変更します。またビルトインWebサーバの起動時にドキュメントルートとして webapp ディレクトリを指定するようにします。

  • カレントディレクトリ
    • webapp
    • chat.php
    • data
    • chat.txt

新しいディレクトリ構成について確認していきましょう。まずカレントディレクトリ( /Users/your_name/Desktop/code-php など)に webapp ディレクトリと data ディレクトリを作成します。 webapp ディレクトリにはPHPのプログラム( chat.php )を配置し、 data ディレクトリにはデータを扱うファイル( chat.txt )を配置します。

ディレクトリ構成を変更したことでチャットプログラム( chat.php )にも一部修正が必要になります。

<?php
$file = "../data/chat.txt";
$messages = file($file, FILE_IGNORE_NEW_LINES);
if ($_SERVER["REQUEST_METHOD"] === "POST") {
  $message = (string)filter_input(INPUT_POST, "message");
  if ($message !== "") {
    $messages[] = $message;
    file_put_contents($file, $message . PHP_EOL,
                                  FILE_APPEND | LOCK_EX);
  }
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>PHP Sample</title>
</head>
<body>
  <h3>Chat</h3>
  <hr>
  <form action="chat.php" method="post">
    <input type="text" name="message">
    <input type="submit" value="send">
  </form>
  <ul>
    <?php for ($i=0; $i < count($messages); $i++) { ?>
    <li><?php echo htmlspecialchars($messages[$i]); ?></li>
    <?php } ?>
  </ul>
</body>
</html>

ここでは先頭部分の chat.txt ファイルのパスを修正しています。

$file = "../data/chat.txt";

ここでは相対パス指定で data ディレクトリに配置した chat.txt を参照できるように修正しています。先頭の ../ の部分は親ディレクトリを意味しており、 chat.php ファイルの所属する webapp ディレクトリから1つ上位のディレクトリに上がり、そこから data ディレクトリ下にある chat.txt ファイルを指定しています。このようにPHPのプログラムはドキュメントルートの外に配置しているファイルにもアクセス可能です。

プログラムを修正したら、一度ビルトインWebサーバを停止します。それからビルトインWebサーバを起動します。このとき -t オプション(ドキュメントルート)に webapp ディレクトリを指定します。

$ php -S localhost:8000 -t webapp

上記のように起動することで、ビルトインWebサーバのドキュメントルートを webapp ディレクトリに変更できます。

それではWebブラウザを開いてアドレスバーからチャット画面( chat.php )にアクセスしてみましょう。

http://localhost:8000/chat.php

表示されたチャット画面では以前と同じようにメッセージを投稿できます。

送信ボタンをクリックすると次のように表示されます。

またテキストエディタで chat.txt ファイルを確認してみると正しくメッセージを追記できているのがわかります。

Hello World!
<script>alert('Script Injection!')</script>
Change DocRoot

それから以前のようにアドレスバーから直接 chat.txt ファイルにもアクセスしてみましょう。

http://localhost:8000/chat.txt

そうすると以前のような chat.txt ファイルへのアクセスは失敗し、 Not Found という表示されたエラー画面を確認できるでしょう。

このようにデータを扱うファイルの配置場所を工夫することで、Webブラウザからの直接的なアクセスを禁止できます。

まとめ

  • ドキュメントルート以下に配置したファイルは公開されてしまう
  • 重要なファイルはドキュメントルート以下に配置してはいけない
  • PHPプログラムからはサーバ上の非公開ディレクトリにもアクセスできる