gihyo.jp » DEVELOPER STAGE » 連載 » なぜPHPアプリにセキュリティホールが多いのか? » 第11回 スクリプトインジェクションを防ぐ10のTips

なぜPHPアプリにセキュリティホールが多いのか?

第11回 スクリプトインジェクションを防ぐ10のTips

前回はスクリプトインジェクションがなくならない理由を紹介しました。それをふまえて今回はスクリプトインジェクションを防ぐ10のTipsを紹介します。

デフォルト文字エンコーディングを指定

php.iniには,PHPが生成した出力の文字エンコーディングをHTTPヘッダで指定するdefault_charsetオプションがあります。文字エンコーディングは必ずHTTPヘッダレベルで指定しなければなりません。しかし,デフォルト設定ではdefault_charsetが空の状態で,アプリケーションで設定しなければ,HTTPヘッダでは文字エンコーディングが指定されない状態になります。

HTTPヘッダで文字エンコーディングを指定しない場合,スクリプトインジェクションに脆弱になる場合あるので,default_charsetには“UTF-8”を指定することをお勧めします。サイトによってはSJIS,EUC-JP,ISO-2022-JPなどを利用していると思います。これらのサイトでUTF-8に設定すると文字化けが発生する可能性があります。しかし,default_charset="UTF-8"を設定して文字化けが発生する場合,アプリケーション側で文字エンコーディングを設定していないことになり修正が必要であることが分かるので,問題を未然に防ぐことができます。

UTF-8をお勧めするには理由があります。例えば,EUC-JP文字エンコーディングを利用しているサイトでSJISをデフォルト文字エンコーディングに設定すると,アプリケーションによってはスクリプトインジェクションが可能になります。UTF-8なら安全,とは言えませんが,ほかの日本語文字エンコーディングよりは安全なデフォルト設定だと言えます。

アプリケーションを作る場合,必ず文字エンコーディングを明示的にスクリプトから設定するようにします。

ini_set('default_charset', 'UTF-8');

アプリケーションで文字エンコーディングを設定している場合でも,万が一設定漏れがあった場合に備えてphp.iniやWebサーバの設定ファイルでアプリケーションが使用しているデフォルト文字エンコーディングを指定したほうがよいです。以下の設定はApache Webサーバのhttpd.confや.htaccessで利用できます。

php_value default_charset "UTF-8"

文字エンコーディングを入力時にチェック

すべてのWebアプリケーションはブラウザなどから入力を受け取った際に,必ず文字エンコーディングが正しいかチェックしなければなりません。文字エンコーディングが壊れていないかチェックしないと,思いもよらない箇所で問題が発生する場合があります。例えば,PHP5.2.5では壊れたUTF-8文字エンコーディングを利用しhtmlentities,htmlspecialcharsによるエスケープを回避できる問題が修正されました。文字エンコーディングが正しいかチェックし,不正な場合はセキュリティエラーとしてスクリプトの実行を停止していれば,htmlentities/htmlspecialcharsに脆弱性がある状態でも安全にこれらの関数を利用できます。

Webアプリケーションから入力されたデータはWebアプリケーションのみでなく,ほかのアプリケーションなどでも利用される場合も少なくありません。ほかのアプリケーションがデータを安全に処理するためにも,文字エンコーディングのチェックは欠かせません。

文字エンコーディングのチェックにはmb_check_encoding関数を利用します。PHP4とPHP5両方で利用できます。

入力文字列は厳格にバリデーション

よくあるインジェクション系の脆弱性の原因は入力チェック不足であることがほとんどです。データベースレコードIDが整数であるにも関わらず0から9の文字のみで構成されているかチェックしていない等です。日本国内の電話番号なら1,2,3,4,5,6,7,8,9,0,-のからなる12または13文字になります。

すべての入力はアプリケーションが期待している文字,形式および長さを満たしているかチェックしなければなりません。「バリデーションはインジェクション対策でない」といった意見を稀に聞きます。しかし,厳格な入力バリデーションが行われていないアプリケーションの安全性検証は,厳格な入力バリデーションが行われているアプリケーションに比べて非常に困難です。

厳格な入力のバリデーションはすべてのセキュリティ対策の基本です。必ず厳格な入力バリデーションを行うようにします。

出力する場合はエスケープした出力をデフォルトに設定

アプリケーションではechoやprint文など,文字列を直接出力する関数は利用しないようにします。簡単なラッパー関数を作成し,デフォルトではエスケープして出力するようにします。

define('ESCAPE_HTML', 1);
define('ESCAPE_URL', 2);
define('NOESCAPE', 3);

funtion p($str, $escape=ESCAPE_HTML, $encoding='UTF-8') {
   switch ($escape) {
      case ESCAPE_HTML:
         echo htmlentities($str, ENT_QUOTES, $encoding);
         break;
      case ESCAE_URL:
         echo rawurlencode($str);
         break;
      case NOESCAPE:
         echo $str;
         break;
      default:
         trigger_error('Invalid option');
         exit;
   }
}

p('<script>alert(1)</script>'); // デフォルトではHTMLエスケープされる

この考え方はWebアプリケーションのみでなく多くのアプリケーションに取り入れられています。HTMLを使用しているのはWebブラウザだけではありません。SkypeなどのクライアントアプリケーションでもメッセージがHTMLタグで記述されており,デフォルトでエスケープする仕様に変更された際にタグがそのまま見えていた,などの事例はよくあります。Webアプリケーション開発フレームワークなどでもすべての出力はデフォルトでHTML用にエスケープされるフレームワークもあります。

エスケープせずに出力する場合,確実に安全であることを確認

100%の安全性を保証できる場合にのみエスケープ無しで出力します。例えば,データベースからの取得した整数型のデータであっても,データが本当に整数型であるかは値をチェックしないと保証できません。データベースによっては整数型のコラムでも文字列が保存可能なデータベースもあります。整数型のコラムと思っていたコラムが文字列型であるかも知れません。プログラム中でいちいちこのような心配をするのは面倒です。整数型であっても,ひとつ前のTipのようにエスケープしてしまうほうが安全で確実です。

ブラウザがどのような文字列でJavaScriptを実行するかはブラウザの実装により異なります。下記のXSS Cheat Sheetを参照すると,直観的にはJavaScriptを実行できるとわかりづらい文字列でもJavaScriptを実行してしまうことがわかります。

XSS Cheat Sheet
http://ha.ckers.org/xss.html

strip_tags関数では許可タグを設定しない

PHPにはHTMLタグを削除してくれるstrip_tagsと呼ばれる関数があります。この関数には許可するHTMLタグを指定できますが,タグを許可した場合,そのタグの属性もすべて残ったままになります。つまり,strip_tags関数で許可するタグを指定した場合,関数の戻り値をそのまま出力するとスクリプトインジェクションに脆弱になります。

例えば<b>タグを許可した場合,

text

などと記述されていると簡単にJavaScriptが実行できます。

許可するタグを指定したい場合はDOMやSAXを利用します。

HTMLのパースに正規表現は利用しない

ユーザから送信されたテキスト中に含まれるタグをエスケープしないで出力する場合,許可するタグとそのタグで許可する属性を抽出しなければなりません。タグと属性を抽出するためにはテキストをパースしなければなりません。最も手軽な方法は正規表現を利用しテキストをパースする方法です。しかし,正規表現を利用してテキストを適切にパースするのは簡単ではありません。HTMLをパースする場合,XMLやDOMを処理するモジュールを利用します。

タグや属性を出力する場合は厳格なホワイトリストで確認

タグや属性を出力する場合,許可するタグとその属性と値を明確に定義します。特に属性値は厳格に処理しないとJavaScriptなどの混入を許してしまう場合があります。

許可するタグや属性と値は基本的にすべてホワイトリスト形式でチェックします。例えば,ユーザがCSSスタイル名を指定できるようにする場合,ユーザが指定可能なスタイル名を配列に保存し,配列に保存されたスタイル名と一致するかどうかチェックします。任意の文字列を処理したい場合は可能な限り限定した文字列のみ許可するようにします。

CSSファイル生成に注意を払う

CSSファイルの生成にPHPを利用する場合,JavaScriptが実行されないように注意しなければなりません。ユーザ入力値をCSSファイル生成に利用する場合,タグや属性と値をスクリプトから設定するのと同じようにホワイトリスト方式でユーザ入力値をチェックします。

JavaScript生成に注意を払う

PHPでJavaScriptファイルを生成する場合,ユーザ入力をそのまま出力すると任意のJavaSriptの実行が可能になります。PHPでJavaScriptを出力する場合には,文字列,コンテクストに応じてホワイトリスト方式でのチェックやエスケープを行ってから出力しなければなりません。ユーザ入力を利用したJavaScriptの生成はできる限り行わないほうがよいでしょう。

著者プロフィール

大垣靖男(おおがきやすお)

University of Denver卒。同校にてコンピュータサイエンスとビジネスを学ぶ。株式会社シーエーシーを経て,エレクトロニック・サービス・イニシアチブ有限会社を設立。
オープンソース製品は比較的古くから利用し,Linuxは0.9xのころから利用している。オープンソースシステム開発への参加はエレクトロニック・サービス・イニシアチブ設立後から。PHPプロジェクトでは,PostgreSQLモジュールのメンテナンスを担当している。

URLhttp://blog.ohgaki.net/

著書

  • Webアプリセキュリティ対策入門〜あなたのサイトは大丈夫?

    Webアプリセキュリティ対策入門〜あなたのサイトは大丈夫?

  • [改訂版]PHPポケットリファレンス

    [改訂版]PHPポケットリファレンス

コメント

コメントの記入

一行クイックアンケート

gihyo.jpで取り上げてほしいネタは?

その他の連載

なぜPHPアプリにセキュリティホールが多いのか?

「PHPのセキュリティは最悪だ」とよく聞きませんか? 本連載では,そのあたりの本当のところを探りながら,Webアプリケーションのセキュリティ対策について考えます。

Webデザイン業界の三位一体モデル

キャンペーンサイト,ブランディングサイト等に関わっているキープレイヤー,広告主,Webクリエイター(制作会社),広告代理店の三者のそれぞれの立場をインタビューすることで,Web広告寄りの視点から,これからのWebデザイン業界の未来を探ります。

今からスタート! PHP

この連載では,これからPHPをはじめようと考えている方にむけて,プログラミングのために必要な準備や,基本的なプログラミングの方法などを紹介していきます。

[動画で解説]和田卓人の“テスト駆動開発”講座

テスト駆動開発(TDD)についての,動画による講義形式の連載です。テスト駆動開発を知るために,経験者の話を聞く,という点からみなさんのお役に立てればと考えています。

Eclipseプラグインを作ってみよう!

Eclipseには,ユーザー独自のプラグインを開発するための環境として,プラグイン開発環境(PDE)が用意されています。この連載では,Eclipse Formsを使った設定ファイルエディターの開発を通じて,Eclipseプラグイン開発手法を紹介していきます。

Subversion+svkでらくらく分散リポジトリ

バージョン管理ソフトSubversionの基礎からバグトラッキングシステム(BTS)との連携,Subversionのサブプロジェクトとして始まったsvkによる分散リポジトリ管理について紹介します。

オープンソースなシステム自動管理ツール Puppet

UNIX系OSのシステム管理を自動で行うためのツールPuppetについて,その概要から具体的なシステム管理への適用まで,実際の現場で利用するために必要な情報をお届けします。

組み合わせテストをオールペア法でスピーディに!

この特集では,ソフトウェアの組み合わせテストについての技法である「オールペア法」と,オールペア法を採用したテストケース作成ツール「PICT」の機能,およびその効果的な使い方を,多くの例を用いて解説していきます。

連載一覧

おすすめムック

  • ネットワークセキュリティ Expert 7

    ネットワークセキュリティ Expert 7

    ネットワークセキュリティに関する最新情報が満載の『ネットワークセキュリティExpert』第7弾です。本号では,ゼロデイ攻撃やボットネットなど,昨今大きな脅威となって...

  • Java Expert #02

    Java Expert #02

    最先端Java技術情報誌の最新号がついに登場!第2弾となる今回は,前号に引き続きTeedaをまるごと解説します。加えて,2007年のJava業界を席巻した「JRuby」,そして来年...

おすすめムック一覧

gihyo.jp

  • DEVELOPER STAGE
  • ADMINISTRATOR STAGE
  • WEB+DESIGN STAGE
  • LIFESTYLE STAGE
  • SCIENCE STAGE

書籍案内

  • 新刊書籍
  • 書籍ジャンル一覧
  • 書籍シリーズ一覧
  • 新刊ピックアップ
  • ロングセラー
  • 電脳会議

定期刊行物一覧

  • Software Design
  • WEB+DB PRESS
  • Web Site Expert
  • エンジニアマインド
  • 組込みプレス

最近のコメント