3K Views
September 11, 11
スライド概要
徳丸本に学ぶ 安全な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コンサルティング株式会社 代表 – 京セラコミュニケーションシステム株式会社 技術顧問 – 独立行政法人情報処理推進機構 非常勤研究員 Copyright © 2011 HASH Consulting Corp. http://www.hash-c.co.jp/ http://www.kccs.co.jp/security/ http://www.ipa.go.jp/security/ 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=13 OR TRUE を指定 $id = $_REQUEST['id']; // 投稿を検査する 投稿のオーナーであることのチェック $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
http://d.hatena.ne.jp/ajiyoshi/20100409/1270809525 より引用 18
鉄則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-FRAMEOPTIONSヘッダを指定する(徳丸本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