Recommended
9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O...
WebAssemblyのWeb以外のことぜんぶ話す
SPAセキュリティ入門~PHP Conference Japan 2021
分散トレーシング技術について(Open tracingやjaeger)
Mercari JPのモノリスサービスをKubernetesに移行した話 PHP Conference 2022 9/24
コンテナの作り方「Dockerは裏方で何をしているのか?」
CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例
セキュリティを楽しむ(CTFとbugbountyの始め方)
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
乗っ取れコンテナ!!開発者から見たコンテナセキュリティの考え方(CloudNative Days Tokyo 2021 発表資料)
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptx
IoT時代におけるストリームデータ処理と急成長の Apache Flink
ここが変だよ、グローバルスタンダードの脆弱性対策~入力値の考え方~
More Related Content
9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O...
WebAssemblyのWeb以外のことぜんぶ話す
SPAセキュリティ入門~PHP Conference Japan 2021
What's hot (20)
分散トレーシング技術について(Open tracingやjaeger)
Mercari JPのモノリスサービスをKubernetesに移行した話 PHP Conference 2022 9/24
コンテナの作り方「Dockerは裏方で何をしているのか?」
CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例
セキュリティを楽しむ(CTFとbugbountyの始め方)
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
乗っ取れコンテナ!!開発者から見たコンテナセキュリティの考え方(CloudNative Days Tokyo 2021 発表資料)
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptx
IoT時代におけるストリームデータ処理と急成長の Apache Flink
Viewers also liked (20)
ここが変だよ、グローバルスタンダードの脆弱性対策~入力値の考え方~
徳丸本に載っていないWebアプリケーションセキュリティ
CMS四天王への攻撃デモを通じて、WordPressの効果的な防御法を学ぼう
An Introduction to CSS Frameworks
「これを買っている人はこれも買っています」実装してみた
Battle of the Front-End Frameworks: Bootstrap vs. Foundation
phpMyAdminにおけるスクリプト実行可能な脆弱性3種盛り合わせ
WAS Forum 2010カンファレンス:ケータイ2.0が開けてしまったパンドラの箱
UnicodeによるXSSとSQLインジェクションの可能性
徳丸本に学ぶ 安全なPHPアプリ開発の鉄則2012
SecurityとValidationの奇妙な関係、あるいはDrupalはなぜValidationをしたがらないのか
Similar to 徳丸本に学ぶ 安全なPHPアプリ開発の鉄則2011 (20)
今日こそわかる、安全なWebアプリの作り方2010
『例えば、PHPを避ける』以降PHPはどれだけ安全になったか
第一回 社内勉強会 PHP Application Security Checklist に学ぶ PHP セキュリティ (Excerpt)
【10人限定】1日でマスター!word pressのための「php:mysql講座」
20090218 第5回「PhpによるWebアプリケーションのセキュリティ入門」
PHP初心者セッション2023 〜ChatGPT時代の簡単な始め方〜
Phpcon tokyo 20120_bigginer
ウェブアプリのセキュリティをちゃんと知ろう (毎週のハンズオン勉強会の資料)
文字コードの脆弱性はこの3年間でどの程度対策されたか?
PHPCON_TOKYO_2022_Bigginer.pptx
More from Hiroshi Tokumaru (20) 脅威分析の手法によりウェブサーバーにウイルス対策ソフトが必要かを検証する
introduction to unsafe deserialization part1
SSRF対策としてAmazonから発表されたIMDSv2の効果と破り方
XXE、SSRF、安全でないデシリアライゼーション入門
ウェブ・セキュリティ基礎試験(徳丸基礎試験)の模擬試験問題
オニギリペイのセキュリティ事故に学ぶ安全なサービスの構築法 (PHPカンファレンス2019)
Railsエンジニアのためのウェブセキュリティ入門
デバッガでWordPress本体やプラグインの脆弱性を追いかけてみよう
著名PHPアプリの脆弱性に学ぶセキュアコーディングの原則
脆弱性は誰のせい? PHP、MySQL、Joomla! の責任やいかに
Webサイトをめぐるセキュリティ状況と効果的な防御方法(WordPress編)
Rails SQL Injection Examplesの紹介
徳丸本に学ぶ 安全なPHPアプリ開発の鉄則20113. 徳丸浩の自己紹介
• 経歴
– 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
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
14. 入力処理では何をするか
• 文字エンコーディングの妥当性検証
• 文字エンコーディングの変換
• 入力値検証(バリデーション)
– バリデーションはアプリケーションの正常な動作を担保するためで、
脆弱性対策ではない
– 入力値の文字種と文字数のチェック
– 必須項目が入力されているか
• セキュリティの観点からは以下に注意
– 制御文字のチェック(ヌルバイト、改行、その他の制御文字)
– いわゆるブラックリスト検査をするのではなく、正常系の文字種を定
義しよう(いわゆるホワイトリスト検査)
• よくヌルバイトや改行を弾くサンプルを見かけるが、他の制御文字は許すこと
になってしまう
• 詳しくは、徳丸本4.2節で
Copyright © 2011 HASH Consulting Corp. 14
16. 安全なSQLライブラリの基準は
• 以下がポイント
– 静的プレースホルダが使えること
– 文字エンコーディング指定ができる
– 文字エンコーディングが正しく反映される(5C問題など)
– バックスラッシュのエスケープにDBの設定が反映される
• MySQL: NO_BACKSLASH_ESCAPES
バックスペースをエスケープしない
• PostgreSQL: standard_conforming_strings
• メンテナンスが継続されていること
• 「安全なSQLの呼び出し方」に詳しく説明
• 同書では、MDB2を推奨している
• PHP5.3.8以降では、ようやくPDOも使えるレベルになった
Copyright © 2011 HASH Consulting Corp. 16
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
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
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
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
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