スクリプト挿入攻撃のセキュリティメモ : PHP

Pocket

スクリプト挿入攻撃への対策メモ。

情報処理推進機構:情報セキュリティ:脆弱性対策:安全なウェブサイトの作り方はスクリプト挿入攻撃の対策が書かれている(p24, 1.5.1)。

  1. 出力要素はエスケープ処理する。
  2. URLの出力はhttp://,https://で始まるURLだけを許可する。
  3. <script>….</script>を動的に作成しない。
  4. スタイルシートを任意のサイトから取り込めるようにしない。
  5. HTTPレスポンスヘッダのContent-Typeに文字コードを指定する。

上記の1,2に関するメモ。

magic_quotes_gpc

php.iniのmagic_quotes_gpcがOnのとき$_GET, $_POST, $_COOKIEのパラメータに含まれるシングルクォート、ダブルクォート、バックスラッシュは自動的に\でエスケープされる。下記のコードはmagic_quotes_gpcがOffを前提としている。

出力要素のエスケープ処理

getメソッド

getはフォームの内容をパーセントエンコードしURLの?以下にクエリ文字列として付けて送る。
クエリ文字列はkey=valueを&でつなぐ。

リクエスト http://www.example.com/index.php?key1=a&key2=b

上記リクエストのステータスライン。

GET /get.php?key1=a&key2=b HTTP/1.1

postメソッド

postメソッドはフォームの値をURLエンコードしてボディとしてサーバーに送る。
ボディはkey=valueを&でつなぐ。
Content-Typeはapplication/x-www-form-urlencoded。

PHPの$_GET, $_POST, $_REQUEST

リクエストのメソッドが予想できるときは$_REQUESTは使わずメソッドに応じて$_POST, $_GETを使う。

リクエストURL http://example.com/index.php?url=http%3A%2F%2Fexample.com

上記のgetリクエストのときは$_POSTでは値を取得できない。

<?php
    $getURL = $_GET['url']; // ← http://example.com
    $postURL = $_POST['url']; // 空文字

» HTTPの基礎 : HTTP | FindxFine -Web制作に関するメモ-
» パーセントエンコーディングとURLエンコード | FindxFine -Web制作に関するメモ-

Script Insertion

HTMLを出力するときにデータを適切にエスケープしないと意図しないスクリプトを挿入される。
たとえばJavaScriptはwindow.location.hrefでリダイレクトできる。
HTMLとして出力するデータに下記スクリプトを含んでいるとhttp://www.example.comへリダイレクトされる。

<script>window.location.href="http://www.example.com";</script>

問題のあるコードを

<?php
header("Content-type: text/html; charset=UTF-8");
if (isset($_GET['url']) && $_GET['url'] !== '') {
    $url = $_GET['url'];
    echo <<<EOF
<html>
<head>
<title>JavaScriptでリダイレクト</title>
</head>
<body>
$url
</body>
</html>
EOF;
} else {
    echo <<< FORM
<html>
<head>
<title>JavaScriptでリダイレクト</title>
</head>
<body>
<form action="get.php" method="GET">
     <input type="text" name="url" size="40">
    <input type="submit" value="送信">
</form>
</body>
</html>
FORM;
}

リダイレクト用のスクリプト。

<script>window.location.href="http://www.example.com";</script>

上記をパーセントエンコーディングした値をクエリ文字として追加してアクセスする(スクリプトのURLはwww.example.net/index.phpとする)。

http://www.example.net/index.php?%3cscript%3ewindow%2elocation%2ehref%3d%22http%3a%2f%2fwww%2eexample%2ecom%22%3b%3c%2fscript%3e

http://www.example.comへリダイレクトされる。

対策は出力データを適切にエスケープする。具体的には<>&”‘をhtmlspechalchars関数でHTMLエンティティへエスケープする。

<?php
header("Content-type: text/html; charset=UTF-8");
if (isset($_GET['url']) && $_GET['url'] !== '') {
    $url = $_GET['url'];
    $output = htmlspecialchars($url, ENT_QUOTES, 'UTF-8');
    echo <<<EOF
<html>
<head>
<title>JavaScriptでリダイレクト</title>
</head>
<body>
$output
</body>
</html>
EOF;
} else {
    echo <<< FORM
<html>
<head>
<title>JavaScriptでリダイレクト</title>
</head>
<body>
<form action="get.php" method="GET">
     <input type="text" name="url" size="40">
    <input type="submit" value="送信">
</form>
</body>
</html>
FORM;
}

htmlspecialchars関数を使うと適切にエスケープされる。

%3cscript%3ewindow%2elocation%2ehref%3d%22http%3a%2f%2fwww%2eexample%2ecom%22%3b%3c%2fscript%3e

エスケープされた出力。

&lt;script&gt;window.location.href=&quot;http://www.example.com&quot;;&lt;/script&gt;

パーセントエンコーディング(URLエンコーディング)

URLで使用するべきでない文字を%xx(xxは16進数)を使い符号化することをパーセントエンコーディングという。パーセントエンコーディングはURLエンコードとも言う。フォームデータをポストする際の符号化(application/x-www-form-urlencoded)もURLエンコードと言うので本記事ではURLの符号化はパーセントエンコード、フォームデータの符号化はURLエンコードと書く。パーセントエンコーディングとURLエンコードは半角スペースの処理が異なる。

» パーセントエンコーディングとURLエンコード | FindxFine -Web制作に関するメモ-

URLの出力はhttp://,https://で始まるURLだけ許可

aタグのhref属性, imgのsrc属性, formのaction属性などに擬似スキームjavascript:を書くことでスクリプトを実行できる1

<a href="javascript: alert('sample'); void(0);">Sample</a>

上記は多くのブラウザでSampleをクリックするとアラートダイアログを表示する。
擬似スキームの挿入に対してはhttp://とhttps://で始まるURLのみ許可するホワイトリストを行う。

ちなみに下記のようなコードはスクリプトを実行しない。

<a href="http://javascript: alert('sample'); void(0);">Sample</a>

セキュリティの資料

» 情報処理推進機構:情報セキュリティ:脆弱性対策:安全なウェブサイトの作り方
» パーフェクトPHP (PERFECT SERIES 3)


  1. 擬似スキームは他にもある。 

コメント

No comments yet.

コメントの投稿

改行と段落タグは自動で挿入されます。
メールアドレスは表示されません。