Help us understand the problem. What is going on with this article?

【初学者向け】セキュリティ対策入門①〜XSS編〜

前提

確認環境

以下と同様です。
【初学者向け】セキュリティ対策入門⓪〜環境構築編〜

本シリーズの目的

以下と同様です。
【初学者向け】セキュリティ対策入門⓪〜環境構築編〜

本記事の目標

XSS(クロスサイトスクリプティング)の概要、原因、対策について理解することです。

本記事を読み進める上での必要事項

以下の内容を終えていることです。
【初学者向け】セキュリティ対策入門⓪〜環境構築編〜

概要

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

不正なスクリプトを混入・実行させることです。掲示板などエンドユーザからの入力値をWebページに表示させる機能を持ったWebアプリケーション全般で行われる可能性があります。

これだけだとわかりにくいと思いますので実際に見てみましょう。

実際に体験してみよう

本シリーズで使うコンテナを起動して
http://localhost:8080/xss/bad.php?name=J
にアクセスしてみましょう。

『こんにちは、Jさん』とブラウザに表示されていると思います。これはnameパラメータの内容をもとに挨拶文言を表示させているものです。ソースコードはtutorial-php-security/www/html/xss/bad.phpにあります。

tutorial-php-security/www/html/xss/bad.php
<?php
$name = $_GET['name'];
?>

<p>こんにちは、<?= $name; ?>さん</p>

$_GET['name']でクエリストリングスのnameパラメータを参照しています。これが上述するところの『エンドユーザからの入力値』の一例です。クエリストリングスだけではなく、POST送信で渡ってきたデータやDBに格納されたデータを出力する場合も、エンドユーザの入力によるものであれば同様です。

次に
http://localhost:8080/xss/bad.php?name=<script>alert(1)</script>
にアクセスしてみましょう。

以下2点が重要です。

  1. ダイアログが表示
  2. ダイアログで『OK』をクリックしたのち『こんにちは、さん』と表示

何が起きているかというとnameパラメータの<script>alert(1)</script>がスクリプトと見なされてJavaScriptのコードが実行されてしまっているのです。alert()はダイアログを表示させるJavaScriptの関数です。

今回は単にダイアログが表示されただけなので大したことがないと思うかもしれません。しかし、別のサーバにリダイレクトさせられたりCookie情報を盗まれてしまったり様々な被害が生じてしまいます。

原因

不正なスクリプトを表示させていることです。これを避けるにあたって様々な対策があります。その一部を以下で具体的に紹介していきます。

対策

エスケープする

以下にアクセスしてみましょう。

http://localhost:8080/xss/good.php?name=<script>alert(1)</script>

bad.phpではなくgood.phpにアクセスしていることに注意しましょう。実際にアクセスすると『ダイアログが表示されない』『「こんにちは、<script>alert(1)</script>さん」と表示されている』ことがわかると思います。

good.phpではある処理を追加しています。それを次に確認しましょう。

tutorial-php-security/www/html/xss/good.php
<?php
$name = $_GET['name'];
?>

<p>こんにちは、<?= htmlspecialchars($name, ENT_QUOTES | ENT_HTML5, 'UTF-8'); ?>さん</p>

ポイントはhtmlspecialchars()の部分です。これはエスケープするための関数です。エスケープとは<>などHTMLにおいて特殊な意味を持つ文字列をそれぞれ&lt;&gt;など安全な文字列に置き換えることです。詳細は『文字参照』などで検索してみてください。&lt;は画面上では<と表示されるため『こんにちは、<script>alert(1)</script>さん』と表示されているわけです。

そもそも出力しない

エスケープが機能しない場合もあります。たとえば

<script><?= $js_code; ?></script>
<a href=<?= $link_url; ?>>危ないリンク</a>

というケースを考えてみましょう。

前者ではalert(2)という文字列が$js_codeに格納されている場合、エスケープしたところで意味がありません。bad.phpと同様ダイアログが表示してしまいます。

後者ではJavaScript:alert(3)という文字列が$link_urlに格納されている場合、エスケープしたところで意味がありません。bad.phpと同様ダイアログが表示してしまいます。ちなみにJavaScript:XXXのような記述をJavaScript擬似プロトコルといいます。JavaScript擬似プロトコルで記述できる箇所ではエスケープが意味を成しません。

こういう場合では、ユーザが入力したデータをそのまま出力しない仕様にするのが得策です。

入力チェックを行う

ユーザの入力をDBに格納するときやユーザの入力データを出力する際に、入力チェックを行うことも有効です。極端な例ですが、nameパラメータに12という文字列以外入力を認めないようにバックエンドでチェックすればスクリプトは混入しなくなります。ちなみに、フロントエンドでの入力チェックやHTMLタグの属性などエンドユーザ側で書き換えできてしまうチェック方法は意味がないので気をつけてください。

ライブラリを使う

ブログアプリケーションを作成するときのように、ユーザにタグ入力を認める機能を実装する場合は、ユーザの入力データからスクリプトだけを上手く取り除くロジックが必要です。それを0から作るのはあまり現実的ではないためライブラリを導入ことが検討に値する解決策となります。

一例ですがHTML Purifierというものがあります。

参考文献

独習PHP 第3版

今回の内容は以上です。最後までご覧いただきありがとうございました。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away