徳丸本に学ぶ
 安全なPHPアプリ開発の鉄則2011




                      2011年9月10日
           HASHコンサルティング株式会社
                               徳丸 浩
                 twitter id: ockeghem
本日お話しする内容
• 鉄則10
• 鉄則9
• 鉄則8
• 鉄則7
• 鉄則6
• 鉄則5
• 鉄則4
• 鉄則3
• 鉄則2
• 鉄則1

         Copyright © 2011 HASH Consulting Corp.   2
徳丸浩の自己紹介
• 経歴
  – 1985年 京セラ株式会社入社
  – 1995年 京セラコミュニケーションシステム株式会社(KCCS)に出向・転籍
  – 2008年 KCCS退職、HASHコンサルティング株式会社設立
• 経験したこと
  – 京セラ入社当時はCAD、計算幾何学、数値シミュレーションなどを担当
  – その後、企業向けパッケージソフトの企画・開発・事業化を担当
  – 1999年から、携帯電話向けインフラ、プラットフォームの企画・開発を担当
      Webアプリケーションのセキュリティ問題に直面、研究、社内展開、寄稿などを開始
  – 2004年にKCCS社内ベンチャーとしてWebアプリケーションセキュリティ事業を立ち上げ
• その他
  – 1990年にPascalコンパイラをCabezonを開発、オープンソースで公開
    「大学時代のPascal演習がCabezonでした」という方にお目にかかることも
• 現在
  – HASHコンサルティング株式会社 代表                                  http://www.hash-c.co.jp/
  – 京セラコミュニケーションシステム株式会社 技術顧問                            http://www.kccs.co.jp/security/
  – 独立行政法人情報処理推進機構 非常勤研究員                                http://www.ipa.go.jp/security/


                Copyright © 2011 HASH Consulting Corp.                               3
本を書きました




      2011年3月5日初版第1刷
      2011年7月28日 初版第4刷


                   4
史上最強のレビュアー軍団
大崎雅幸 太田良典 かいと(kaito834)
加藤泰文 小邨孝明 坂井隆二 下岡葉子
髙木正弘 竹迫良範 東内裕二 塙与志夫
日野洋一郎 山崎圭吾 山下太郎
Masahiro Yamada(masa141421356)
山本陽平



         Copyright © 2011 HASH Consulting Corp.   5
鉄則10
安全なPHP入門書で
学習する


   Copyright © 2011 HASH Consulting Corp.   6
安全なPHP入門書って?




 Copyright © 2011 HASH Consulting Corp.   7
そこそこでも安全なPHP入門書には
  出会ったことがない (;´Д`)




    Copyright © 2011 HASH Consulting Corp.   8
せめてXSSとSQLインジェクションくらい
 は最初から正しく教えて欲しい(_ _)



  この2つは対策箇所が多いので後から直すも大変ですし




       Copyright © 2011 HASH Consulting Corp.   9
一見対策している*つもり*の例
    しかし、このプログラムではIDさえ指定すれば、誰でもどの投稿でも削除でき
    てしまいます。そこで、様々なチェックを行ってから削除しています。

if (isset($_SESSION['id'])) {
  $id = $_REQUEST['id'];
  // 投稿を検査する
  $sql = sprintf('SELECT * FROM posts WHERE id=%d',
              mysql_real_escape_string($id));
  $record = mysql_query($sql) or die(mysql_error());
  $table = mysql_fetch_assoc($record);
  if ($table['member_id'] == $_SESSION['id']) {
     // 削除
     mysql_query('DELETE FROM posts WHERE id=' .
        mysql_real_escape_string($id)) or die(mysql_error());
  }
}



       よくわかるPHPの教科書、たにぐちまこと著、毎日コミュニケーションズ、2010より引用         10
一見対策している*つもり*の例
    しかし、このプログラムではIDさえ指定すれば、誰でもどの投稿でも削除でき
    てしまいます。そこで、様々なチェックを行ってから削除しています。

if (isset($_SESSION['id'])) {
  $id = $_REQUEST['id'];       id=13 OR TRUE を指定
  // 投稿を検査する 投稿のオーナーであることのチェック
  $sql = sprintf('SELECT * FROM posts WHERE id=%d',
              mysql_real_escape_string($id));
                        SELECT * FROM posts WHERE id=13
  $record = mysql_query($sql) or die(mysql_error());
  $table = mysql_fetch_assoc($record);
  if ($table['member_id'] == $_SESSION['id']) {
     // 削除           このユーザの投稿であることを確認
     mysql_query('DELETE FROM posts WHERE id=' .
        mysql_real_escape_string($id)) or die(mysql_error());
               DELETE FROM posts WHERE id=13 OR TRUE
  }
}
                            全ての投稿を削除


       よくわかるPHPの教科書、たにぐちまこと著、毎日コミュニケーションズ、2010より引用         11
鉄則9
入力-処理-出力で適切
な処理を行うこと


   Copyright © 2011 HASH Consulting Corp.   12
Webアプリケーションの機能と脆弱性の対応




徳丸本P68から引用
             Copyright © 2011 HASH Consulting Corp.   13
入力処理では何をするか
• 文字エンコーディングの妥当性検証
• 文字エンコーディングの変換
• 入力値検証(バリデーション)
 – バリデーションはアプリケーションの正常な動作を担保するためで、
   脆弱性対策ではない
 – 入力値の文字種と文字数のチェック
 – 必須項目が入力されているか
• セキュリティの観点からは以下に注意
 – 制御文字のチェック(ヌルバイト、改行、その他の制御文字)
 – いわゆるブラックリスト検査をするのではなく、正常系の文字種を定
   義しよう(いわゆるホワイトリスト検査)
   • よくヌルバイトや改行を弾くサンプルを見かけるが、他の制御文字は許すこと
     になってしまう
• 詳しくは、徳丸本4.2節で
           Copyright © 2011 HASH Consulting Corp.   14
鉄則8
安全なSQLライブラリを
選定して正しく使う


   Copyright © 2011 HASH Consulting Corp.   15
安全なSQLライブラリの基準は
• 以下がポイント
 – 静的プレースホルダが使えること
 – 文字エンコーディング指定ができる
 – 文字エンコーディングが正しく反映される(5C問題など)
 – バックスラッシュのエスケープにDBの設定が反映される
   • MySQL: NO_BACKSLASH_ESCAPES
                                                            バックスペースをエスケープしない
   • PostgreSQL: standard_conforming_strings
• メンテナンスが継続されていること
• 「安全なSQLの呼び出し方」に詳しく説明
• 同書では、MDB2を推奨している
• PHP5.3.8以降では、ようやくPDOも使えるレベルになった

                   Copyright © 2011 HASH Consulting Corp.                16
参考




http://blog.tokumaru.org/2011/08/pdo.html   17
18
http://d.hatena.ne.jp/ajiyoshi/20100409/1270809525 より引用
鉄則7
XSS対策の第一歩は
htmlspecialcharsを正
しく使うことから

     Copyright © 2011 HASH Consulting Corp.   19
みなさん、htmlspecialcharsを
  正しく使っていますか?




     Copyright © 2011 HASH Consulting Corp.   20
htmlspecialcharの正しい使い方
• 第2引数はENT_QUOTESでなくても本当はよい
 – ENT_QUOTESを使わないと脆弱性という人までいる(;´Д`)
 – 要素内容は、どれを指定してもOK
 – ダブルクオートで囲った属性値は、ENT_COMPATか
   ENT_QUOTES
 – シングルクォートで囲った属性値はENT_QUOTES
 – 属性値はダブルクォートで囲むことにすれば、ENT_COMPATで
   統一してもOK
 – 参考:徳丸本P102
• 第3引数は文字エンコーディングを正しく指定すること
 – 指定する文字エンコーディングはmbstring.internal_encoding
 – 省略時はISO-8859-1 (Latin-1) / 5.4 からはUTF-8
• htmlentitiesの方が安全という説は間違い(根拠がない)
               Copyright © 2011 HASH Consulting Corp.   21
XSS対策の基礎の基礎
• HTTPレスポンスヘッダに文字エンコーディングを指定する
 – header('Content-Type: text/html; charset=UTF-8');
• 要素内容は前述のhtmlspecialcharsの使い方
• 属性値はhtmlspecialcharsでエスケープした値をダブル
  クォートで囲む
• src属性などにURLを動的生成する場合は、スキームに注意
 – http:// か https:// か / で始まることを確認
• JavaScriptのリテラルを動的生成することはとても危険
 – イベントハンドラの場合は、JSエスケープした値をHTMLエスケープ
 – script要素内はとてもめんどくさいので、やらない方が賢明
 – どうしてもやりたいなら、「過剰エスケープ」(徳丸本P113)
 – hiddenパラメータに書いてDOMで読むのが無難(徳丸本P114)
                Copyright © 2011 HASH Consulting Corp.   22
鉄則6
ファイルアップロードは
罠がいっぱい


   Copyright © 2011 HASH Consulting Corp.   23
ファイルアップロードの危険性
• アップロードしたファイルをPHPスクリプトとして実行される
 – PHPに限らず、JSP、ASPなどのスクリプトとして解釈される可能性
 – CGIは実行権限が必要なので、通常は成立しない
   • 書き込みの際に権限を過剰に設定していると成立する可能性も
• アップロードしたファイルをHTMLと誤認させるXSS
 – 不適切なContent-Type設定が主要因
 – IEに注意。画像のマジックバイトのチェックは必須
   • getimagesizeが便利 (徳丸本P278)
   • IE8以上は X-Content-Type-Options: nosniff が有効
     (徳丸本には間に合わず)
• 詳しくは徳丸本4.12 P258~



                 Copyright © 2011 HASH Consulting Corp.   24
PHP逆引きレシピのアップロードサンプル
        if (strlen($_FILES['uploadfile']['name'][$i]) > 0) {
        # 画像ファイルの拡張子を取得して判定します。
           $imgType = $_FILES['uploadfile']['type'][$i];
           $extension = '';
           if ($imgType == 'image/gif') {
             $extension = 'gif';
           } else if ($imgType == 'image/png' || $imgType == 'image/x-png') {
             $extension = 'png';
           } else if ($imgType == 'image/jpeg' || $imgType == 'image/pjpeg') {
             $extension = 'jpg';
           } else if ($extension == '') {
             $error .= '許可されていない拡張子です<br />';
           }
        # getimagesize()関数で画像かどうかの判定をします。
           $checkImage = @getimagesize($_FILES['uploadfile']['tmp_name'][$i]);
           if ($checkImage == FALSE) {
             $error .= '画像ファイルをアップロードしてください<br />';
           } else if ($imgType != $checkImage['mime']) {
             $error .= '拡張子が異なります<br />';
           } else if ($_FILES['uploadfile']['size'][$i] > 102400) {
        # 画像ファイルのサイズ上限をチェックします。
             $error .= 'ファイルサイズが大きすぎます。100KB以下にしてください<br />';
かなり良い      } else if ($_FILES['uploadfile']['size'][$i] == 0) {
        # 画像ファイルのサイズ下限をチェックします。
のだが惜し        $error .= 'ファイルが存在しないか空のファイルです<br />';
           } else if ($extension != 'gif' && $extension != 'jpg' && $extension != 'png') {
いところも   # 画像ファイルの拡張子をチェックします。
             $error .= 'アップロード可能なファイルはgif、jpgまたはpngのみです<br />';
           } else {
        # ここでは格納ディレクトリの下に「"upfile_" + 現在のタイムスタンプ + 連番 + 拡張
        子」で配置します。
             $moveTo = $filePath . '/upfile_' . time() . $i . '.' . $extension;
                                                                                          25
PHP逆引きレシピ・サンプルの残念なところ
• チェックが厳しすぎて、IE8以前で、PNG画像のアップロード
  がエラーになる
 – IE8まで、ブラウザが送信するMIMEはimage/x-png
 – MIMEのチェック部分では考慮している
 – getimagesizeが返すMIMEはimage/pngなのでエラーになる(;´Д`)
• ファイル名の生成に現在時刻(秒単位)を使っているので
  ファイル名の衝突の可能性
 – 同一時刻であれば、「遅いもの勝ち」となる
 – 状況によっては脆弱性となる
   • 画像管理ソフトで、Aさんは「恥ずかしい画像」を非公開ファイルとして投稿、
     Bさんは、画像を公開ファイルとして投稿
   • たまたま同一時刻なのでファイル名が同一となる
   • Bさんの公開画像として、Aさんの「恥ずかしい画像」が公開
   • Aさん、Bさんともに、恥ずかしいことに(;´Д`)
             Copyright © 2011 HASH Consulting Corp.   26
PHP逆引きレシピ・サンプルの残念なところ
• チェックが厳しすぎて、IE8以前で、PNG画像のアップロード
  がエラーになる
 – IE8まで、ブラウザが送信するMIMEはimage/x-png
         でも、全体としては、
 – MIMEのチェック部分では考慮している
            逆引きレシピはかなりいいよ
 – getimagesizeが返すMIMEはimage/pngなのでエラーになる(;´Д`)
• ファイル名の生成に現在時刻(秒単位)を使っているので
  ファイル名の衝突の可能性
 – 同一時刻であれば、「遅いもの勝ち」となる
 – 状況によっては脆弱性となる
   • 画像管理ソフトで、Aさんは「恥ずかしい画像」を非公開ファイルとして投稿、
     Bさんは、画像を公開ファイルとして投稿      ユニークなファイル名生成
   • たまたま同一時刻なのでファイル名が同一となる                           の例は、徳丸本P266参照
   • Bさんの公開画像として、Aさんの「恥ずかしい画像」が公開
   • Aさん、Bさんともに、恥ずかしいことに(;´Д`)
             Copyright © 2011 HASH Consulting Corp.               27
鉄則5
今時文字コードのセキュ
リティ気にしなくていい
のは小学生までだよね

   Copyright © 2011 HASH Consulting Corp.   28
文字コードのセキュリティまとめ
• 文字コードの基本的なところを勉強しよう(徳丸本6章)
 – 文字集合:ASCII、ISO-8859-1、JIS X 0208、…Unicode
 – 文字符号化形式:Shift_JIS、EUC-JP、UTF-8、UTF-16
• 文字コードを正しく扱う基本
 – 入力:文字エンコーディングの妥当性チェック
 – 処理:処理中に文字集合を変更しない
      マルチバイト対応の関数を使う(mbstring系)
 – 出力:文字コードの指定を正しく行う
   • HTTPレスポンスヘッダの文字エンコーディング指定
   • SQL接続時の文字エンコーディング指定
 – 設定:php.iniの正しい文字コード設定
• 文字エンコーディングの妥当性チェックで防げない脆弱性に
  注意
               Copyright © 2011 HASH Consulting Corp.   29
文字コードの妥当性チェックで防げない脆弱性の例
~5C問題によるSQLインジェクション~




   PHP5.3.5までのPDOの話
   現在は、DB接続時に文字エンコーディングを指定すれば問題ない

           Copyright © 2010 HASH Consulting Corp.   30
鉄則4
2010年代のWebサイト
はクリックジャッキング
対策しよう

   Copyright © 2011 HASH Consulting Corp.   31
クリックジャッキング攻撃
• ターゲットの画面をiframe上で「透明に」表示する
• その下にダミーの画面を表示させる。ユーザにはダミーの画
  面が透けて見える
• 利用者がダミーの画面上のボタンを押すと、実際には全面の
  ターゲット画面のボタンが押される




        本当の画面(前面、透明)                  ダミーの画面(後面)

• 続きはデモで
           Copyright © 2011 HASH Consulting Corp.   32
クリックジャッキングの対策
• クリックジャッキングの影響はクロスサイト・リクエストフォー
  ジェリ(CSRF)と同等
 – ユーザの意識とは無関係に、ユーザの権限で操作が行われる
• クリックジャッキングされると困るページには、X-FRAME-
  OPTIONSヘッダを指定する(徳丸本P63)
 – frame/iframeを禁止して良い場合
 – header('X-FRAME-OPTIONS', 'DENY');

 – frame/iframeを禁止できないが単一ホストの場合
 – header('X-FRAME-OPTIONS', 'SAMEORIGIN');
• CSRF対策のトークン発行しているページが対象となる
• メタ要素によるX-FRAME-OPTIONS指定は無効です。
  徳丸本第3刷までの記述は間違いです(_ _)
              Copyright © 2011 HASH Consulting Corp.   33
鉄則3
パスワードの保存は
hash(pass . salt)の
繰り返し(Stretching)

     Copyright © 2011 HASH Consulting Corp.   34
どうして暗号化ではなくてハッシュなの?
• 暗号化の場合、鍵の管理が難しい
• アプリケーションは鍵を使わなければならないが、攻撃者には鍵を見せ
  たくない
• PSNの事件では、権限昇格されたことになっているので、暗号鍵も盗ま
  れていると想定せざるを得ない
• ハッシュだと鍵を使わないので、鍵管理のわずらわしさがない
• パスワードをサイト管理者にも知られたくないというニーズも
  – 暗号化されたパスワードだと、サイト管理者やヘルプデスク担当者がパスワードを
    知り得るのが嫌だ
  – ヘルプデスクに見せないようにするには、サポート用画面の機能次第で可
  – 管理者の悪事は総合的な対策が必要で、パスワードの問題だけではない
• PCI-DSS2.0 8.4項には「8.4 強力な暗号化を使用して、すべてのシス
  テムコンポーネントでの伝送および保存中のすべてのパスワードを読
  み取り不能にする」とあり、ハッシュを求めてはいない

             Copyright © 2011 HASH Consulting Corp.   35
ハッシュで保存されたパスワードは本当に安全なの?
• 一般的に、(暗号論的)ハッシュ値から平文を「復元する」ことはできな
  い
 – 「password」のMD5ハッシュ: 5f4dcc3b5aa765d61d8327deb882cf99
• しかし、パスワードの場合は特別な事情がある
• 例:4桁の暗証番号をハッシュ値で保存している場合
 – 全ての可能性は1万通りしかないのだから、総当たりで確認すれば、平文の暗証
   番号はすぐに判明する
• 原理は8桁パスワードでも同じ
• ハッシュ保存の場合、アルゴリズムは攻撃者が知っている前提で安全
  な設計とする
 – 平文パスワード以外は、すべて「ばれている」想定を置く
• 攻撃者にとって未知であることが保証された情報があれば、それを鍵と
  して暗号化すればよい。現実にはそのような保証がないから暗号化を
  用いない

                  Copyright © 2011 HASH Consulting Corp.   36
Saltってなに?
• ソルト(Salt)とは、ハッシュの元データ(パスワード)に追加する文字列
• 見かけのパスワードの長さを長くする
 – 公開されたレインボーテーブルは10文字までのパスワードに対応しているので、
   パスワードとソルトを合わせて20文字以上にしておけば、当面は大丈夫
• ユーザ毎にソルトを変えることで、パスワードが同じでも、異なるハッ
  シュ値が得られる
• ソルトの要件
 – ある程度の長さを確保すること
 – ユーザ毎に異なるものにすること
• ソルトには乱数を用いることが多いが、乱数が必須というわけではない
  (暗号論的に安全な乱数である必要はもちろんない)
• ソルトは秘密情報ではない。ソルトは、通常ハッシュ値と一緒に保存す
  る


            Copyright © 2011 HASH Consulting Corp.   37
Stretchingってなに?
• ストレッチング(Stretching)とは、ハッシュの計算を繰り返すこと
• ハッシュの計算を遅くすることにより、辞書攻撃や総当たり攻撃に対抗
  する
• 1万回ストレッチすると、「 GPU で 7 時間である」が7万時間になる計算
  – 7万時間 = 2916日 = 約8年
• 「悪い」パスワードまで救えるわけではない
  – 「password」というパスワードをつけていたら、100万回ストレッチしてもすぐに解
    読されてしまう
• 十分長いパスワードをつけてもらえば、ストレッチングは必要ない
  – 1文字パスワードを長くすることは、約100回のストレッチングに相当する。パス
    ワードを2文字長くしてもらえば…
  – でも、中々難しいのでストレッチングの値打ちがある
• ストレッチングはメリットとデメリットがあるので、導入の有無と回数をよ
  く検討すること
                 Copyright © 2011 HASH Consulting Corp.   38
鉄則2
PHPのバージョンアップ
にとことん付き合う信念


   Copyright © 2011 HASH Consulting Corp.   39
PHPのバージョンアップにタイムリーに追随しよう
• PHPは脆弱性もあるが、基本的には迅速に対応している
• 基本的にはバージョンアップによりPHPの脆弱性対応を行う
 – Linuxディストリビューションの配布するパッチを利用することも可
• サイト稼働中のPHPメジャーバージョンアップの可能性を考
  慮しておくこと

          PHP5.x
          PHP4.x
          PHP3.x


                                                     3.5年




  1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010
                    Copyright © 2011 HASH Consulting Corp.           40
鉄則1
徳丸本を買ってよく読め

 ご清聴ありがとうございました

   Copyright © 2011 HASH Consulting Corp.   41

徳丸本に学ぶ 安全なPHPアプリ開発の鉄則2011

  • 1.
    徳丸本に学ぶ 安全なPHPアプリ開発の鉄則2011 2011年9月10日 HASHコンサルティング株式会社 徳丸 浩 twitter id: ockeghem
  • 2.
    本日お話しする内容 • 鉄則10 • 鉄則9 •鉄則8 • 鉄則7 • 鉄則6 • 鉄則5 • 鉄則4 • 鉄則3 • 鉄則2 • 鉄則1 Copyright © 2011 HASH Consulting Corp. 2
  • 3.
    徳丸浩の自己紹介 • 経歴 – 1985年 京セラ株式会社入社 – 1995年 京セラコミュニケーションシステム株式会社(KCCS)に出向・転籍 – 2008年 KCCS退職、HASHコンサルティング株式会社設立 • 経験したこと – 京セラ入社当時はCAD、計算幾何学、数値シミュレーションなどを担当 – その後、企業向けパッケージソフトの企画・開発・事業化を担当 – 1999年から、携帯電話向けインフラ、プラットフォームの企画・開発を担当 Webアプリケーションのセキュリティ問題に直面、研究、社内展開、寄稿などを開始 – 2004年にKCCS社内ベンチャーとしてWebアプリケーションセキュリティ事業を立ち上げ • その他 – 1990年にPascalコンパイラをCabezonを開発、オープンソースで公開 「大学時代のPascal演習がCabezonでした」という方にお目にかかることも • 現在 – HASHコンサルティング株式会社 代表 http://www.hash-c.co.jp/ – 京セラコミュニケーションシステム株式会社 技術顧問 http://www.kccs.co.jp/security/ – 独立行政法人情報処理推進機構 非常勤研究員 http://www.ipa.go.jp/security/ Copyright © 2011 HASH Consulting Corp. 3
  • 4.
    本を書きました 2011年3月5日初版第1刷 2011年7月28日 初版第4刷 4
  • 5.
    史上最強のレビュアー軍団 大崎雅幸 太田良典 かいと(kaito834) 加藤泰文小邨孝明 坂井隆二 下岡葉子 髙木正弘 竹迫良範 東内裕二 塙与志夫 日野洋一郎 山崎圭吾 山下太郎 Masahiro Yamada(masa141421356) 山本陽平 Copyright © 2011 HASH Consulting Corp. 5
  • 6.
    鉄則10 安全なPHP入門書で 学習する Copyright © 2011 HASH Consulting Corp. 6
  • 7.
    安全なPHP入門書って? Copyright ©2011 HASH Consulting Corp. 7
  • 8.
    そこそこでも安全なPHP入門書には 出会ったことがない(;´Д`) Copyright © 2011 HASH Consulting Corp. 8
  • 9.
    せめてXSSとSQLインジェクションくらい は最初から正しく教えて欲しい(_ _) この2つは対策箇所が多いので後から直すも大変ですし Copyright © 2011 HASH Consulting Corp. 9
  • 10.
    一見対策している*つもり*の例 しかし、このプログラムではIDさえ指定すれば、誰でもどの投稿でも削除でき てしまいます。そこで、様々なチェックを行ってから削除しています。 if (isset($_SESSION['id'])) { $id = $_REQUEST['id']; // 投稿を検査する $sql = sprintf('SELECT * FROM posts WHERE id=%d', mysql_real_escape_string($id)); $record = mysql_query($sql) or die(mysql_error()); $table = mysql_fetch_assoc($record); if ($table['member_id'] == $_SESSION['id']) { // 削除 mysql_query('DELETE FROM posts WHERE id=' . mysql_real_escape_string($id)) or die(mysql_error()); } } よくわかるPHPの教科書、たにぐちまこと著、毎日コミュニケーションズ、2010より引用 10
  • 11.
    一見対策している*つもり*の例 しかし、このプログラムではIDさえ指定すれば、誰でもどの投稿でも削除でき てしまいます。そこで、様々なチェックを行ってから削除しています。 if (isset($_SESSION['id'])) { $id = $_REQUEST['id']; id=13 OR TRUE を指定 // 投稿を検査する 投稿のオーナーであることのチェック $sql = sprintf('SELECT * FROM posts WHERE id=%d', mysql_real_escape_string($id)); SELECT * FROM posts WHERE id=13 $record = mysql_query($sql) or die(mysql_error()); $table = mysql_fetch_assoc($record); if ($table['member_id'] == $_SESSION['id']) { // 削除 このユーザの投稿であることを確認 mysql_query('DELETE FROM posts WHERE id=' . mysql_real_escape_string($id)) or die(mysql_error()); DELETE FROM posts WHERE id=13 OR TRUE } } 全ての投稿を削除 よくわかるPHPの教科書、たにぐちまこと著、毎日コミュニケーションズ、2010より引用 11
  • 12.
    鉄則9 入力-処理-出力で適切 な処理を行うこと Copyright © 2011 HASH Consulting Corp. 12
  • 13.
  • 14.
    入力処理では何をするか • 文字エンコーディングの妥当性検証 • 文字エンコーディングの変換 •入力値検証(バリデーション) – バリデーションはアプリケーションの正常な動作を担保するためで、 脆弱性対策ではない – 入力値の文字種と文字数のチェック – 必須項目が入力されているか • セキュリティの観点からは以下に注意 – 制御文字のチェック(ヌルバイト、改行、その他の制御文字) – いわゆるブラックリスト検査をするのではなく、正常系の文字種を定 義しよう(いわゆるホワイトリスト検査) • よくヌルバイトや改行を弾くサンプルを見かけるが、他の制御文字は許すこと になってしまう • 詳しくは、徳丸本4.2節で Copyright © 2011 HASH Consulting Corp. 14
  • 15.
  • 16.
    安全なSQLライブラリの基準は • 以下がポイント –静的プレースホルダが使えること – 文字エンコーディング指定ができる – 文字エンコーディングが正しく反映される(5C問題など) – バックスラッシュのエスケープにDBの設定が反映される • MySQL: NO_BACKSLASH_ESCAPES バックスペースをエスケープしない • PostgreSQL: standard_conforming_strings • メンテナンスが継続されていること • 「安全なSQLの呼び出し方」に詳しく説明 • 同書では、MDB2を推奨している • PHP5.3.8以降では、ようやくPDOも使えるレベルになった Copyright © 2011 HASH Consulting Corp. 16
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
    htmlspecialcharの正しい使い方 • 第2引数はENT_QUOTESでなくても本当はよい –ENT_QUOTESを使わないと脆弱性という人までいる(;´Д`) – 要素内容は、どれを指定してもOK – ダブルクオートで囲った属性値は、ENT_COMPATか ENT_QUOTES – シングルクォートで囲った属性値はENT_QUOTES – 属性値はダブルクォートで囲むことにすれば、ENT_COMPATで 統一してもOK – 参考:徳丸本P102 • 第3引数は文字エンコーディングを正しく指定すること – 指定する文字エンコーディングはmbstring.internal_encoding – 省略時はISO-8859-1 (Latin-1) / 5.4 からはUTF-8 • htmlentitiesの方が安全という説は間違い(根拠がない) Copyright © 2011 HASH Consulting Corp. 21
  • 22.
    XSS対策の基礎の基礎 • HTTPレスポンスヘッダに文字エンコーディングを指定する –header('Content-Type: text/html; charset=UTF-8'); • 要素内容は前述のhtmlspecialcharsの使い方 • 属性値はhtmlspecialcharsでエスケープした値をダブル クォートで囲む • src属性などにURLを動的生成する場合は、スキームに注意 – http:// か https:// か / で始まることを確認 • JavaScriptのリテラルを動的生成することはとても危険 – イベントハンドラの場合は、JSエスケープした値をHTMLエスケープ – script要素内はとてもめんどくさいので、やらない方が賢明 – どうしてもやりたいなら、「過剰エスケープ」(徳丸本P113) – hiddenパラメータに書いてDOMで読むのが無難(徳丸本P114) Copyright © 2011 HASH Consulting Corp. 22
  • 23.
    鉄則6 ファイルアップロードは 罠がいっぱい Copyright © 2011 HASH Consulting Corp. 23
  • 24.
    ファイルアップロードの危険性 • アップロードしたファイルをPHPスクリプトとして実行される –PHPに限らず、JSP、ASPなどのスクリプトとして解釈される可能性 – CGIは実行権限が必要なので、通常は成立しない • 書き込みの際に権限を過剰に設定していると成立する可能性も • アップロードしたファイルをHTMLと誤認させるXSS – 不適切なContent-Type設定が主要因 – IEに注意。画像のマジックバイトのチェックは必須 • getimagesizeが便利 (徳丸本P278) • IE8以上は X-Content-Type-Options: nosniff が有効 (徳丸本には間に合わず) • 詳しくは徳丸本4.12 P258~ Copyright © 2011 HASH Consulting Corp. 24
  • 25.
    PHP逆引きレシピのアップロードサンプル if (strlen($_FILES['uploadfile']['name'][$i]) > 0) { # 画像ファイルの拡張子を取得して判定します。 $imgType = $_FILES['uploadfile']['type'][$i]; $extension = ''; if ($imgType == 'image/gif') { $extension = 'gif'; } else if ($imgType == 'image/png' || $imgType == 'image/x-png') { $extension = 'png'; } else if ($imgType == 'image/jpeg' || $imgType == 'image/pjpeg') { $extension = 'jpg'; } else if ($extension == '') { $error .= '許可されていない拡張子です<br />'; } # getimagesize()関数で画像かどうかの判定をします。 $checkImage = @getimagesize($_FILES['uploadfile']['tmp_name'][$i]); if ($checkImage == FALSE) { $error .= '画像ファイルをアップロードしてください<br />'; } else if ($imgType != $checkImage['mime']) { $error .= '拡張子が異なります<br />'; } else if ($_FILES['uploadfile']['size'][$i] > 102400) { # 画像ファイルのサイズ上限をチェックします。 $error .= 'ファイルサイズが大きすぎます。100KB以下にしてください<br />'; かなり良い } else if ($_FILES['uploadfile']['size'][$i] == 0) { # 画像ファイルのサイズ下限をチェックします。 のだが惜し $error .= 'ファイルが存在しないか空のファイルです<br />'; } else if ($extension != 'gif' && $extension != 'jpg' && $extension != 'png') { いところも # 画像ファイルの拡張子をチェックします。 $error .= 'アップロード可能なファイルはgif、jpgまたはpngのみです<br />'; } else { # ここでは格納ディレクトリの下に「"upfile_" + 現在のタイムスタンプ + 連番 + 拡張 子」で配置します。 $moveTo = $filePath . '/upfile_' . time() . $i . '.' . $extension; 25
  • 26.
    PHP逆引きレシピ・サンプルの残念なところ • チェックが厳しすぎて、IE8以前で、PNG画像のアップロード がエラーになる – IE8まで、ブラウザが送信するMIMEはimage/x-png – MIMEのチェック部分では考慮している – getimagesizeが返すMIMEはimage/pngなのでエラーになる(;´Д`) • ファイル名の生成に現在時刻(秒単位)を使っているので ファイル名の衝突の可能性 – 同一時刻であれば、「遅いもの勝ち」となる – 状況によっては脆弱性となる • 画像管理ソフトで、Aさんは「恥ずかしい画像」を非公開ファイルとして投稿、 Bさんは、画像を公開ファイルとして投稿 • たまたま同一時刻なのでファイル名が同一となる • Bさんの公開画像として、Aさんの「恥ずかしい画像」が公開 • Aさん、Bさんともに、恥ずかしいことに(;´Д`) Copyright © 2011 HASH Consulting Corp. 26
  • 27.
    PHP逆引きレシピ・サンプルの残念なところ • チェックが厳しすぎて、IE8以前で、PNG画像のアップロード がエラーになる – IE8まで、ブラウザが送信するMIMEはimage/x-png でも、全体としては、 – MIMEのチェック部分では考慮している 逆引きレシピはかなりいいよ – getimagesizeが返すMIMEはimage/pngなのでエラーになる(;´Д`) • ファイル名の生成に現在時刻(秒単位)を使っているので ファイル名の衝突の可能性 – 同一時刻であれば、「遅いもの勝ち」となる – 状況によっては脆弱性となる • 画像管理ソフトで、Aさんは「恥ずかしい画像」を非公開ファイルとして投稿、 Bさんは、画像を公開ファイルとして投稿 ユニークなファイル名生成 • たまたま同一時刻なのでファイル名が同一となる の例は、徳丸本P266参照 • Bさんの公開画像として、Aさんの「恥ずかしい画像」が公開 • Aさん、Bさんともに、恥ずかしいことに(;´Д`) Copyright © 2011 HASH Consulting Corp. 27
  • 28.
  • 29.
    文字コードのセキュリティまとめ • 文字コードの基本的なところを勉強しよう(徳丸本6章) –文字集合:ASCII、ISO-8859-1、JIS X 0208、…Unicode – 文字符号化形式:Shift_JIS、EUC-JP、UTF-8、UTF-16 • 文字コードを正しく扱う基本 – 入力:文字エンコーディングの妥当性チェック – 処理:処理中に文字集合を変更しない マルチバイト対応の関数を使う(mbstring系) – 出力:文字コードの指定を正しく行う • HTTPレスポンスヘッダの文字エンコーディング指定 • SQL接続時の文字エンコーディング指定 – 設定:php.iniの正しい文字コード設定 • 文字エンコーディングの妥当性チェックで防げない脆弱性に 注意 Copyright © 2011 HASH Consulting Corp. 29
  • 30.
    文字コードの妥当性チェックで防げない脆弱性の例 ~5C問題によるSQLインジェクション~ PHP5.3.5までのPDOの話 現在は、DB接続時に文字エンコーディングを指定すれば問題ない Copyright © 2010 HASH Consulting Corp. 30
  • 31.
  • 32.
    クリックジャッキング攻撃 • ターゲットの画面をiframe上で「透明に」表示する • その下にダミーの画面を表示させる。ユーザにはダミーの画 面が透けて見える • 利用者がダミーの画面上のボタンを押すと、実際には全面の ターゲット画面のボタンが押される 本当の画面(前面、透明) ダミーの画面(後面) • 続きはデモで Copyright © 2011 HASH Consulting Corp. 32
  • 33.
    クリックジャッキングの対策 • クリックジャッキングの影響はクロスサイト・リクエストフォー ジェリ(CSRF)と同等 – ユーザの意識とは無関係に、ユーザの権限で操作が行われる • クリックジャッキングされると困るページには、X-FRAME- OPTIONSヘッダを指定する(徳丸本P63) – frame/iframeを禁止して良い場合 – header('X-FRAME-OPTIONS', 'DENY'); – frame/iframeを禁止できないが単一ホストの場合 – header('X-FRAME-OPTIONS', 'SAMEORIGIN'); • CSRF対策のトークン発行しているページが対象となる • メタ要素によるX-FRAME-OPTIONS指定は無効です。 徳丸本第3刷までの記述は間違いです(_ _) Copyright © 2011 HASH Consulting Corp. 33
  • 34.
  • 35.
    どうして暗号化ではなくてハッシュなの? • 暗号化の場合、鍵の管理が難しい • アプリケーションは鍵を使わなければならないが、攻撃者には鍵を見せ たくない • PSNの事件では、権限昇格されたことになっているので、暗号鍵も盗ま れていると想定せざるを得ない • ハッシュだと鍵を使わないので、鍵管理のわずらわしさがない • パスワードをサイト管理者にも知られたくないというニーズも – 暗号化されたパスワードだと、サイト管理者やヘルプデスク担当者がパスワードを 知り得るのが嫌だ – ヘルプデスクに見せないようにするには、サポート用画面の機能次第で可 – 管理者の悪事は総合的な対策が必要で、パスワードの問題だけではない • PCI-DSS2.0 8.4項には「8.4 強力な暗号化を使用して、すべてのシス テムコンポーネントでの伝送および保存中のすべてのパスワードを読 み取り不能にする」とあり、ハッシュを求めてはいない Copyright © 2011 HASH Consulting Corp. 35
  • 36.
    ハッシュで保存されたパスワードは本当に安全なの? • 一般的に、(暗号論的)ハッシュ値から平文を「復元する」ことはできな い – 「password」のMD5ハッシュ: 5f4dcc3b5aa765d61d8327deb882cf99 • しかし、パスワードの場合は特別な事情がある • 例:4桁の暗証番号をハッシュ値で保存している場合 – 全ての可能性は1万通りしかないのだから、総当たりで確認すれば、平文の暗証 番号はすぐに判明する • 原理は8桁パスワードでも同じ • ハッシュ保存の場合、アルゴリズムは攻撃者が知っている前提で安全 な設計とする – 平文パスワード以外は、すべて「ばれている」想定を置く • 攻撃者にとって未知であることが保証された情報があれば、それを鍵と して暗号化すればよい。現実にはそのような保証がないから暗号化を 用いない Copyright © 2011 HASH Consulting Corp. 36
  • 37.
    Saltってなに? • ソルト(Salt)とは、ハッシュの元データ(パスワード)に追加する文字列 • 見かけのパスワードの長さを長くする – 公開されたレインボーテーブルは10文字までのパスワードに対応しているので、 パスワードとソルトを合わせて20文字以上にしておけば、当面は大丈夫 • ユーザ毎にソルトを変えることで、パスワードが同じでも、異なるハッ シュ値が得られる • ソルトの要件 – ある程度の長さを確保すること – ユーザ毎に異なるものにすること • ソルトには乱数を用いることが多いが、乱数が必須というわけではない (暗号論的に安全な乱数である必要はもちろんない) • ソルトは秘密情報ではない。ソルトは、通常ハッシュ値と一緒に保存す る Copyright © 2011 HASH Consulting Corp. 37
  • 38.
    Stretchingってなに? • ストレッチング(Stretching)とは、ハッシュの計算を繰り返すこと • ハッシュの計算を遅くすることにより、辞書攻撃や総当たり攻撃に対抗 する • 1万回ストレッチすると、「 GPU で 7 時間である」が7万時間になる計算 – 7万時間 = 2916日 = 約8年 • 「悪い」パスワードまで救えるわけではない – 「password」というパスワードをつけていたら、100万回ストレッチしてもすぐに解 読されてしまう • 十分長いパスワードをつけてもらえば、ストレッチングは必要ない – 1文字パスワードを長くすることは、約100回のストレッチングに相当する。パス ワードを2文字長くしてもらえば… – でも、中々難しいのでストレッチングの値打ちがある • ストレッチングはメリットとデメリットがあるので、導入の有無と回数をよ く検討すること Copyright © 2011 HASH Consulting Corp. 38
  • 39.
  • 40.
    PHPのバージョンアップにタイムリーに追随しよう • PHPは脆弱性もあるが、基本的には迅速に対応している • 基本的にはバージョンアップによりPHPの脆弱性対応を行う – Linuxディストリビューションの配布するパッチを利用することも可 • サイト稼働中のPHPメジャーバージョンアップの可能性を考 慮しておくこと PHP5.x PHP4.x PHP3.x 3.5年 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 Copyright © 2011 HASH Consulting Corp. 40
  • 41.