[PHP] WEBアプリケーションの脆弱性 - XSS(クロスサイトスクリプティング)脆弱性と対策について

XSS(クロスサイトスクリプティング)についてと、PHPにおけるXSS対策についてまとめます。

XSS(クロスサイトスクリプティング)とは

クロスサイトスクリプティング(以下XSS)とは、Webサイトの脆弱性を突いた悪意のある攻撃のことを言います。

その多くは、スクリプトによってWebページを改ざんしたリンクを用意し、そのリンクを踏んだ第三者の個人情報やID/PASSWORD等の機密情報を抜き取る手口が上げられます。

XSSの概要図

  1. まず攻撃者は、正規のサイトに悪意のあるスクリプトを埋め込みWebページを改ざんします。実際に正規サイトのWebページを書き換えるわけではなく、スクリプトを埋め込んだリンクを用意して、Webページの利用ユーザーがリンクを踏むのを待ちます。
  2. Webページ利用者は、攻撃者が用意したリンクを踏んでしまうと、悪意のあるスクリプトによってWebページが改ざんされた状態でブラウザに表示されます。例えば、ログイン画面のformタグのacsion属性を書き換えられてしまうと、ログイン情報(ID/PASSWORD)が、攻撃者が用意したサーバーにPOSTされてしまう等の被害が考えられます。
  3. 上記の通り改ざんされたWebページから攻撃者の用意したサーバーへ機密情報が送信されたり、偽サイトへ誘導されてしまいます。最初に表示されるページが正規サイトのページなだけに、閲覧者は気づきにくく非常に危険です。

なお、この時のデータの流れが、攻撃者→正規サイト、閲覧者→偽サイト、とクロスすることからクロスサイトスクリプティングと名づけられています。

XSS脆弱性のコード

もっとも簡単な例でXSS脆弱性を再現してみます。

index.html

まずは簡単なFormとSubmitボタンがあるWebページを用意します。

<html>
  <head>
    <title>XSS検証</title>
  </head>
  <body>
    <form action="/xss-test/test.php" method="POST">
      <input type="text" name="value"><br>
      <input type="submit"></input>
    </form>
  </body>
</html>

test.php

サーバー側のコードでは、POSTされたデータを表示しています。

<html>
  <head>
    <title>XSS検証</title>
  </head>
  <body>
    <?php
      $inputValue =  $_POST['value'];
      echo "Hello ", $inputValue, "!!<br>";
    ?>
  </body>
</html>

想定される実行結果

この場合入力した名前がブラウザへ表示されるのが、開発者が想定している動作です。

XSS脆弱性を突いたスクリプトを実行する

以下のようにテキストボックスにスクリプトを入れて実行すると、サーバーから返されたWebページでは入力したスクリプトが動作してしまいBodyタグのstyle属性が変更されてしまいます。攻撃者はこの脆弱性を利用し、閲覧者のブラウザ上でスクリプトによってWebページを改ざんします。

なお、テキストボックスに入力したスクリプトは以下です。

<script>document.body.style='background: #F00;';</script>

PHPにおけるXSS脆弱性対策

上記に示した例のように、ユーザー入力によって動的にWEBページが生成されるような場合は、ユーザー入力の値は適切にエスケープして出力されなくてはなりません。

そこで使用するのが、htmlspecialchars関数、htmlentities関数です。

htmlspecialchars関数

htmlspecialchars関数は、文字列をHTML上で表示する際の形式に変換することが出来ます。具体的にはHTMLに含まれる特殊文字(< > " ' & など)をエスケープすることによってHTML上で表示することが出来るようになります。

1. htmlspecialchars関数の引数
第一引数 string
対象文字列
第二引数 int
変換の種類を示すフラグ(省略可)
  • ENT_COMPAT
    ダブルクオートは変換するが、シングルクオートは変換しない
  • ENT_QUOTES (default)
    ダブルクオートとシングルクオートのどちらも変換する
  • ENT_NOQUOTES
    ダブルクオートとシングルクオートのどちらも変換しない
第三引数 string
文字エンコーディング(省略可)
※省略した場合はdefault_charsetの値

[実装例]入力文字列をHTMLエンコードして表示する

コード

XSS脆弱性のコードで示した例のPHPコード(test.php)を以下のように修正します。

<html>
  <head>
    <title>XSS検証</title>
  </head>
  <body>
    <?php
      $inputValue =  htmlspecialchars($_POST['value'], ENT_QUOTES);
      echo "Hello ", $inputValue, "!!<br>";
    ?>
  </body>
</html>

実行結果

実行結果を確認すると、入力されたスクリプトが文字列として入力されたまま表示されていることが分かります。

なお、この時HTML上には以下のように出力されています。

<html>
  <head>
    <title>XSS検証</title>
  </head>
  <body>
    Hello &lt;script&gt;document.body.style=&#039;background: #F00;&#039;;&lt;/script&gt;!!<br>
  </body>
</html>

コメント

このブログの人気の投稿

docker-compose up で proxyconnect tcp: dial tcp: lookup proxy.example.com: no such host

docker-compose で起動したweb、MySQLに接続できない事象

【PHP】PHP_CodeSnifferを使う(コーディングルールのカスタマイズ)