phpでセキュリティを真面目に考える
DESCRIPTION
オープンソースカンファレンス2011 Hokkaido #osc11do 「PHPでセキュリティを真面目に考える」 LOCAL PHP部 佐藤琢哉(@nazo) http://labs.nazone.info/TRANSCRIPT
PHPで セキュリティを 真面目に考える
オープンソースカンファレンス2011 Hokkaido
LOCAL PHP部 佐藤琢哉(nazo)
配布向け注意事項
この資料はOSC2011Hokkaido用の45分資料を、
配布用に再編集したものです。
セキュリティという広いテーマを扱うのに45
分という時間はすごく足りなく、最初から全
てを網羅するつもりはありません。そのため、
抜けている内容が多いと思いますが、[後で吊
す]タグを付けたりするのはご遠慮下さい。
•
セキュリティネタで他の
セミナーと被るかと思ったので
PHP
のネタがメインです。
•
基本的に初心者~中級者
向けですが、細かい解説は
少ないかもしれません。
今回の内容
これだけ覚えて!
常に最新のPHPを使う
最新のライブラリなどを使う
正しい情報、一次情報を確認する
何も信用しない
自己紹介
佐藤琢哉
nazo
LOCAL PHP部
8月からニートフリーランス
twitter : @nazo
PHPはセキュリティに弱い?
弱い
弱くない
知らない
最強
(nazo脳内調べ)
PHP=セキュリティに弱い という印象
※この内容は現在は修正されています。
なんでそういうイメージなの?
• 利用者が多い
• =レベルが低い人も多い
• PHPに落とし穴が多い
うへへ、よく知らないから適当に
作っちゃうZE☆
警察の ものですがー
知らないことは 罪である
知らないことを 回避するために
「調べられる知識」を 付けることが重要
セキュリティの極意
守破離
守 基礎を知る
破 基礎を実践できるようになる・組み合わせて考えれるようになる
離 自分でセキュリティを考えられるようになる
…それを全て話すと終わらないので
今回はPHPの話
古いPHPを使うとこんなに危険!
最近見つかった脆弱性が修正されていない
脆弱性対策になる関数が入っていない
最新の脆弱性の情報が流れてこない
古いPHP+古いソフトウェアの組み合わせはもっと危険
特定の脆弱性を狙い撃ちにできる
BOT等でその脆弱性だけを無差別に狙う
動作しているプログラムも知られている
ため、簡単に攻撃できる
PHP本体のバグ
基本的にはそれほど多くない
きわどい使い方をするとまれにひっかかる
最新バージョンを使うことが大事
PHP4は使ってはいけない
可能な限りPHP5.3
PHP本体のバグ 最近の例
文字列“2.2250738585072011e-308”をdouble
にキャストするとハングアップする
内部で無限ループになる
32bitプロセスのみで再現
$d = (double)"2.2250738585072011e-308";
PHP5.3.5/PHP5.2.17で修正済
PHPの駄目な設定
safe_mode=On
register_globals=On
magic_quotes_gpc=On
allow_url_include=On
allow_url_fopen=On
error_reporting=E_ALL^E_NOTICE
safe_mode
共用サーバー向けの設定
名前からして、設定すると安全になりそうな風に見えるが…
「他の人のファイル参照を難しくする」程度で、「完全に他の人の
ファイルを参照できなくする」ことはできない。
特に必要がない限りOFFにすべき
自分で設定できるのであれば基本的にOFF
PHP5.3では非推奨(E_DEPRECATED)
PHP6では廃止予定
http://php.net/manual/ja/ini.sect.safe-mode.php
registar_globals
$_GETや$_POSTに入る値をグローバル変数に自動展開
する
グローバル変数の初期値が変わってしまうことにより、
バグになる可能性
外部からやりたい放題になる可能性がある
無条件でOFFにすべき
PHP5.3では非推奨(E_DEPRECATED)
他のregister_xxx系も禁止
magic_quotes_gpc
怪しい記号を¥でエスケープしてくれる
必要がなくてもエスケープされてしまう
漏れるケースが存在する
無条件でOFFにすべき
PHP5.3では非推奨(E_DEPRECATED)
他のmagic_quotes_xxx系も禁止
allow_url_include
include()やrequire()の対象にURLを指定できる
プログラムのバグや、DNSの改ざんなどによって、任
意のプログラムを読み込ませられる可能性が
無条件でOFFにすべき
PHP5.3では非推奨(E_DEPRECATED)
他のallow_url_xxx系も禁止
error_reporting
なぜかE_NOTICEを切っている人が多い
思わぬバグに気づかないことが多い
ちゃんと手抜きせずに修正しよう
可能であればE_STRICTやE_DEPRECATEDも
CMSやフレームワークによっては対応していな
いこともあるので難しい
つまりPHP5.3がいい
危ない設定はE_DEPRECATED
ここで紹介したもの以外にも
E_DEPRECATEDなものがある(eregなど)
エラーをちゃんと表示することが大事
古いPH
P
なんて
廃墟の
ようなもの
PHPには罠のような関数が沢山
セキュリティ意識が低い時代に作られた
PHP6くらいになったら消えてほしい
少しずつE_DEPRECATED入りしている
strip_tags
HTMLタグと思われるものを削除する
誤動作する方法が沢山
絶対に使ってはいけない
htmlspecialcharsを使おう(詳しくは後で)
addslashes
文字列をクオートする
DBにデータを入れる時に使いたくなる
実際には各RDBMSによって特殊な挙動があるため、
脆弱性に繋がる可能性がある
MySQLならmysql_real_escape_string、PostgreSQLな
らpg_escape_stringを使用すべき
htmlspecialcharsと文字コード
htmlspecialcharsの正しい使い方
htmlspecialchars($var, ENT_QUOTES,
'UTF-8');
ENT_QUOTESを指定しないとシングルクオートが変
換されない
文字コードを指定しないと、文字コードに起因する
変換漏れが発生する
文字コード?
Shift_JISで「表」は0x955C
0x5C=¥
0x955Cを、0x95と0x5Cで別々に処理する
関数の場合、0x5C=¥記号を何らかの特殊
記号と判定されてしまう可能性がある
<?php // 「表」をSJISにする $a = mb_convert_encoding('表', 'SJIS-win', 'UTF-8'); // addslashesでエスケープ $b = addslashes($a); // UTF-8に戻す $c = mb_convert_encoding($b, 'UTF-8', 'SJIS-win'); //出力 var_dump($c); => string(4) "表¥"
htmlspecialcharsと文字コード
htmlspcialcharsの例はまた別
詳細はhttp://www.tokumaru.org/d/20090930.html
「htmlspecialchars 文字コード」とかでぐぐれ
PHP5.2.5から、不正な文字エンコーディングをチェッ
クするようになった
それ以前だと意味のない指定なので、必ず最新の
PHPを
そもそもShift_JISは使うな
0x5C(¥)が文字コードに含まれるため危険
Shift_JIS以外だから安全だというわけではないが、
危険要素の多い文字コードなので避けるべき
そもそもUTF-8でほとんどの場合は十分
携帯サイトで出力にShift_JISが要求される場合は、
内部はUTF-8で処理し、入出力時にShift_JISで変換
するのが望ましい
先行バイトによる問題
マルチバイト文字コードの1バイト目だけ
を不正に出力することで、それ以降の文字
をマルチバイト文字の一部として認識さ
せ、本来の役割を破棄させることができる
ブラウザ側で対応されていることが多い
(IE6とかはアウト)
文字コードとPHP
文字コードを考慮されていない関数は危
険
ereg,fgetcsv,addslashes,strlen,etc…
正規表現はpregを、mb_xxxがある関数は
mb_xxxを使用すべき
標準関数だからといって 安心してはいけない
必ず公式ドキュメントなどで 確認を
SQLインジェクションとは
本来正常に実行されるSQL文に、不正なコー
ドを挿入することによって、本来意図しな
いSQL文を実行し、攻撃する攻撃方法
何かの文にDROP DATABASE xxx;とか追加し
て、全データ削除したりとか
他人のパスワードを不正に取得したり
SQLインジェクションの種類
本来1つであるSQL文に、2つ目のSQLを追加
して、任意のSQLを実行させる
1つのSQLのパラメータ指定に、本来指定で
きないパラメータを指定させることによ
り、意図しないデータを取得したり操作し
たりする
PHPとSQLインジェクション
任意のSQLを挿入できるか?
$sql = 'SELECT * FROM hoge WHERE foo = $foo';
$foo = '; DELETE FROM hoge;';
// ここでSQL実行
mysql_query … できない
mysqli_query … できない
pg_query … できる
PDOStatement::execute … できない
問題なSQLインジェクション
例えばSELECT文に穴があってパスワードを
入手できたりとか
例えばDELETE文に穴があって全データ削除
できたりとか
回避方法
プレースホルダが利用可能な場面では、極力
プレースホルダを使用する
プレースホルダを使えない場面で、なるべく
文字列結合で値を渡さないようにする
どうしても文字列結合で値を渡す必要がある
場合は、各DBMSに対応するエスケープ関数で
適切にエスケープする
プレースホルダ
$sql = 'SELECT * FROM hoge WHERE foo = ?;'
$stmt = $mysqli->prepare($sql);
$stmt->bind_param('s', $foo);
$stmt->execute();
エスケープ関数で
$sql = 'SELECT * FROM hoge WHERE foo = %s;'
$new_sql = sprintf($sql, $mysqli-
>real_escape_string($foo));
$mysqli->query($new_sql);
テーブル名は特に危険
$sql = 'SELECT * FROM %s WHERE foo = 1;'
$new_sql = sprintf($sql, $foo);
$mysqli->query($new_sql);
// テーブル名なので'hoge'という指定はできない
// $foo に "hoge INNER JOIN …"とか入ると…?
DBMSと文字コード
不正な文字コードを入れることによって変
なことをさせる攻撃はDBMSにも存在する
mysqlはUTF-8が3byteまでしか入らない(5.5
で対応済)
MySQLのUTF-8
𣗄 や 𣖔 といった文字が入らない
入れようとするとwarningになるが、空として入る
(errorにはならない)
例えばPHP側で入力チェックをして正常に通過して
も、MySQL側には空文字として入ってしまう、という
ことになる
文字チェックはDB側で行うことが必要
SQLインジェクションは 大規模な漏洩事件に 繋がりやすい
PHPは関係ないので概要だけ
ケータイサイトを馬鹿にするな
基本的には普通のサイトと同じ
ケータイからソースが見えなくてもURLが
見えなくても、実際には同じ
PCサイトと同じレベルのチェックが必要
PCサイトより大変な部分も多い
特に最近はJavaScriptも使える
IPアドレスで 制限しておけば
余裕だぜー
いや他にも 脆弱性は あるし…
しかもそのIPアドレスリストちゃんと更新してる?
URLからのセッション乗っ取り
Cookieが使えないケータイブラウザでは、
セッションIDをURLにつけてやりとりする
ことが多い
外部サイトに飛ぶと、refererでセッション
IDが漏れる
そのセッションIDで接続すると…
URLからのセッション乗っ取り:対策
できるだけCookieを使う
セッションの有効期限を短めにする
外部サイトに飛ぶ場合は、必ず1ページ挟み、そこでは
セッションIDは消す
検索エンジンに登録させない・登録させる場合は、
canonical urlを指定する
<link rel="canonical" href="http://example.com"/>
かんたんログインも怖い
ちょっとのミスで攻撃方法が多数
「限りなく防ぐ」方法は存在するが、「完璧に
防ぐ」方法は存在しない
Cookieが使用可能であれば極力Cookieを使
用すべき
ちょっとしたミスで
個人情報が
盗まれている
かもしれない
既存のものを使うということ
「それなりに」信頼性がある
特によく使われていて頻繁に更新されているもの
ほど、安全性が高い(可能性が高い)
特にフレームワーク、CMSは、基礎的な脆弱性が
起こらないような作りになっていることが多
く、下手に自作するよりは安全なことが多い
しかし
使い方を間違えれば脆弱性が生まれる
最新のものを使わないと脆弱性が残ってい
る可能性がある
特にCMSは、見た目で何を使っているかわかりや
すいので、バージョンアップを怠ると狙われや
すい
何が言いたいのか
ライブラリやフレームワークなどは、ちゃんと
メンテされているものであれば、(検証した上
で)積極的に使おう
バージョンアップされている場合は、(検証し
た上で)対応していこう
ライブラリやフレームワークを過度に信用せ
ず、セキュリティチェックは必ず行おう
CakePHPの securityコンポーネントにも 脆弱性があった 時代がありました
脆弱性以前の問題
パスワードはちゃんと設定してますか?
CMSやアプリの管理画面のURLはみんな知って
る
パスワードが簡単だと簡単に入られてしまう
管理画面はIPアドレス制限、BASIC認証などで、
直接見られなくしておいたほうがいい
セキュリティに終わりはない
いつ新しい攻撃方法が発見されるかわか
らない
コンピュータの進化によって不可能が可能
になる場合も
暗号とか
セキュリティ情報を追い続ける
致命的な脆弱性にすぐ対応できるように
→自分のサイトを守るために
→みんなの個人情報を守るために
今回話せなかった内容
XSS(クロスサイトスクリプティング)
セッション関係
CSRF
PHPと関係ない話
その他いろいろ
バグと脆弱性の境界
脆弱性の根本はバグ
バグ=脆弱性 ではない
バグのないプログラムのほうが脆弱性が
少ない可能性が高い
テストなどの、バグを減らすための手法も
実践すべき
バグが出ても…
エラーは画面に表示しない!
display_errors=OFF
開発中はONにしよう
バグがないことが当然だが、最悪の場合のた
め
MySQLが突然死した時にうっかりパスワードが見
えたりとか
セキュリティ情報の探し方
php.net
コピーサイトは見ない
JPCERT/CC
技術系ニュースサイト
(slashdot,gihyo,@IT,etc…)
その他個人ブログなど
とてもいい情報
gihyo.jp「なぜPHPアプリにセキュリティ
ホールが多いのか?」
http://gihyo.jp/dev/serial/01/php-security
IPA「安全なウェブサイトの作り方」
http://www.ipa.go.jp/security/vuln/websecu
rity.html
書籍「体系的に学ぶ 安全なWebアプリケー
ションの作り方」
でも情報を探すのとか難しい
札幌でー
セキュリティのー
勉強会とかー
ないかなー
LOCAL PHP部 参加者募集中!
隔月で勉強会をしています
次回は8月予定
特に内容にこだわりはないので、「これを知
りたい」とか教えてくれれば誰かが用意し
てくれるかもしれません
詳しくは「LOCAL PHP部」で検索!
画像提供(全てCC)
http://www.flickr.com/photos/posteriormente/501245300
6/
http://www.flickr.com/photos/weightlifting/5065942769/
http://www.flickr.com/photos/kentamabuchi/4616039938/
http://www.flickr.com/photos/8mitsu/142336481/
http://www.flickr.com/photos/sotome/2229496414/