phpでセキュリティを真面目に考える

80
PHPセキュリティ真面目考える オープンソースカンファレンス2011 Hokkaido LOCAL PHP部 佐藤琢哉(nazo)

Upload: takuya-sato

Post on 21-May-2015

47.995 views

Category:

Technology


0 download

DESCRIPTION

オープンソースカンファレンス2011 Hokkaido #osc11do 「PHPでセキュリティを真面目に考える」 LOCAL PHP部 佐藤琢哉(@nazo) http://labs.nazone.info/

TRANSCRIPT

Page 1: PHPでセキュリティを真面目に考える

PHPで セキュリティを 真面目に考える

オープンソースカンファレンス2011 Hokkaido

LOCAL PHP部 佐藤琢哉(nazo)

Page 2: PHPでセキュリティを真面目に考える

配布向け注意事項

この資料はOSC2011Hokkaido用の45分資料を、

配布用に再編集したものです。

セキュリティという広いテーマを扱うのに45

分という時間はすごく足りなく、最初から全

てを網羅するつもりはありません。そのため、

抜けている内容が多いと思いますが、[後で吊

す]タグを付けたりするのはご遠慮下さい。

Page 3: PHPでセキュリティを真面目に考える

セキュリティネタで他の

セミナーと被るかと思ったので

PHP

のネタがメインです。

基本的に初心者~中級者

向けですが、細かい解説は

少ないかもしれません。

今回の内容

Page 4: PHPでセキュリティを真面目に考える

これだけ覚えて!

Page 5: PHPでセキュリティを真面目に考える

常に最新のPHPを使う

最新のライブラリなどを使う

正しい情報、一次情報を確認する

何も信用しない

Page 6: PHPでセキュリティを真面目に考える

自己紹介

佐藤琢哉

nazo

LOCAL PHP部

8月からニートフリーランス

twitter : @nazo

Page 7: PHPでセキュリティを真面目に考える

PHPはセキュリティに弱い?

弱い

弱くない

知らない

最強

(nazo脳内調べ)

Page 8: PHPでセキュリティを真面目に考える

PHP=セキュリティに弱い という印象

※この内容は現在は修正されています。

Page 9: PHPでセキュリティを真面目に考える

なんでそういうイメージなの?

• 利用者が多い

• =レベルが低い人も多い

• PHPに落とし穴が多い

Page 10: PHPでセキュリティを真面目に考える

うへへ、よく知らないから適当に

作っちゃうZE☆

警察の ものですがー

Page 11: PHPでセキュリティを真面目に考える

知らないことは 罪である

Page 12: PHPでセキュリティを真面目に考える

知らないことを 回避するために

「調べられる知識」を 付けることが重要

Page 13: PHPでセキュリティを真面目に考える

セキュリティの極意

守破離

Page 14: PHPでセキュリティを真面目に考える

守 基礎を知る

破 基礎を実践できるようになる・組み合わせて考えれるようになる

離 自分でセキュリティを考えられるようになる

Page 15: PHPでセキュリティを真面目に考える

…それを全て話すと終わらないので

今回はPHPの話

Page 16: PHPでセキュリティを真面目に考える
Page 17: PHPでセキュリティを真面目に考える

古いPHPを使うとこんなに危険!

最近見つかった脆弱性が修正されていない

脆弱性対策になる関数が入っていない

最新の脆弱性の情報が流れてこない

Page 18: PHPでセキュリティを真面目に考える

古いPHP+古いソフトウェアの組み合わせはもっと危険

特定の脆弱性を狙い撃ちにできる

BOT等でその脆弱性だけを無差別に狙う

動作しているプログラムも知られている

ため、簡単に攻撃できる

Page 19: PHPでセキュリティを真面目に考える

PHP本体のバグ

基本的にはそれほど多くない

きわどい使い方をするとまれにひっかかる

最新バージョンを使うことが大事

PHP4は使ってはいけない

可能な限りPHP5.3

Page 20: PHPでセキュリティを真面目に考える

PHP本体のバグ 最近の例

文字列“2.2250738585072011e-308”をdouble

にキャストするとハングアップする

内部で無限ループになる

32bitプロセスのみで再現

$d = (double)"2.2250738585072011e-308";

PHP5.3.5/PHP5.2.17で修正済

Page 21: PHPでセキュリティを真面目に考える
Page 22: PHPでセキュリティを真面目に考える

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

Page 23: PHPでセキュリティを真面目に考える

safe_mode

共用サーバー向けの設定

名前からして、設定すると安全になりそうな風に見えるが…

「他の人のファイル参照を難しくする」程度で、「完全に他の人の

ファイルを参照できなくする」ことはできない。

特に必要がない限りOFFにすべき

自分で設定できるのであれば基本的にOFF

PHP5.3では非推奨(E_DEPRECATED)

PHP6では廃止予定

http://php.net/manual/ja/ini.sect.safe-mode.php

Page 24: PHPでセキュリティを真面目に考える

registar_globals

$_GETや$_POSTに入る値をグローバル変数に自動展開

する

グローバル変数の初期値が変わってしまうことにより、

バグになる可能性

外部からやりたい放題になる可能性がある

無条件でOFFにすべき

PHP5.3では非推奨(E_DEPRECATED)

他のregister_xxx系も禁止

Page 25: PHPでセキュリティを真面目に考える

magic_quotes_gpc

怪しい記号を¥でエスケープしてくれる

必要がなくてもエスケープされてしまう

漏れるケースが存在する

無条件でOFFにすべき

PHP5.3では非推奨(E_DEPRECATED)

他のmagic_quotes_xxx系も禁止

Page 26: PHPでセキュリティを真面目に考える

allow_url_include

include()やrequire()の対象にURLを指定できる

プログラムのバグや、DNSの改ざんなどによって、任

意のプログラムを読み込ませられる可能性が

無条件でOFFにすべき

PHP5.3では非推奨(E_DEPRECATED)

他のallow_url_xxx系も禁止

Page 27: PHPでセキュリティを真面目に考える

error_reporting

なぜかE_NOTICEを切っている人が多い

思わぬバグに気づかないことが多い

ちゃんと手抜きせずに修正しよう

可能であればE_STRICTやE_DEPRECATEDも

CMSやフレームワークによっては対応していな

いこともあるので難しい

Page 28: PHPでセキュリティを真面目に考える

つまりPHP5.3がいい

危ない設定はE_DEPRECATED

ここで紹介したもの以外にも

E_DEPRECATEDなものがある(eregなど)

エラーをちゃんと表示することが大事

Page 29: PHPでセキュリティを真面目に考える

古いPH

P

なんて

廃墟の

ようなもの

Page 30: PHPでセキュリティを真面目に考える
Page 31: PHPでセキュリティを真面目に考える

PHPには罠のような関数が沢山

セキュリティ意識が低い時代に作られた

PHP6くらいになったら消えてほしい

少しずつE_DEPRECATED入りしている

Page 32: PHPでセキュリティを真面目に考える

strip_tags

HTMLタグと思われるものを削除する

誤動作する方法が沢山

絶対に使ってはいけない

htmlspecialcharsを使おう(詳しくは後で)

Page 33: PHPでセキュリティを真面目に考える

addslashes

文字列をクオートする

DBにデータを入れる時に使いたくなる

実際には各RDBMSによって特殊な挙動があるため、

脆弱性に繋がる可能性がある

MySQLならmysql_real_escape_string、PostgreSQLな

らpg_escape_stringを使用すべき

Page 34: PHPでセキュリティを真面目に考える

htmlspecialcharsと文字コード

htmlspecialcharsの正しい使い方

htmlspecialchars($var, ENT_QUOTES,

'UTF-8');

ENT_QUOTESを指定しないとシングルクオートが変

換されない

文字コードを指定しないと、文字コードに起因する

変換漏れが発生する

Page 35: PHPでセキュリティを真面目に考える

文字コード?

Shift_JISで「表」は0x955C

0x5C=¥

0x955Cを、0x95と0x5Cで別々に処理する

関数の場合、0x5C=¥記号を何らかの特殊

記号と判定されてしまう可能性がある

Page 36: PHPでセキュリティを真面目に考える

<?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) "表¥"

Page 37: PHPでセキュリティを真面目に考える

htmlspecialcharsと文字コード

htmlspcialcharsの例はまた別

詳細はhttp://www.tokumaru.org/d/20090930.html

「htmlspecialchars 文字コード」とかでぐぐれ

PHP5.2.5から、不正な文字エンコーディングをチェッ

クするようになった

それ以前だと意味のない指定なので、必ず最新の

PHPを

Page 38: PHPでセキュリティを真面目に考える

そもそもShift_JISは使うな

0x5C(¥)が文字コードに含まれるため危険

Shift_JIS以外だから安全だというわけではないが、

危険要素の多い文字コードなので避けるべき

そもそもUTF-8でほとんどの場合は十分

携帯サイトで出力にShift_JISが要求される場合は、

内部はUTF-8で処理し、入出力時にShift_JISで変換

するのが望ましい

Page 39: PHPでセキュリティを真面目に考える

先行バイトによる問題

マルチバイト文字コードの1バイト目だけ

を不正に出力することで、それ以降の文字

をマルチバイト文字の一部として認識さ

せ、本来の役割を破棄させることができる

ブラウザ側で対応されていることが多い

(IE6とかはアウト)

Page 40: PHPでセキュリティを真面目に考える

文字コードとPHP

文字コードを考慮されていない関数は危

ereg,fgetcsv,addslashes,strlen,etc…

正規表現はpregを、mb_xxxがある関数は

mb_xxxを使用すべき

Page 41: PHPでセキュリティを真面目に考える

標準関数だからといって 安心してはいけない

必ず公式ドキュメントなどで 確認を

Page 42: PHPでセキュリティを真面目に考える
Page 43: PHPでセキュリティを真面目に考える

SQLインジェクションとは

本来正常に実行されるSQL文に、不正なコー

ドを挿入することによって、本来意図しな

いSQL文を実行し、攻撃する攻撃方法

何かの文にDROP DATABASE xxx;とか追加し

て、全データ削除したりとか

他人のパスワードを不正に取得したり

Page 44: PHPでセキュリティを真面目に考える

SQLインジェクションの種類

本来1つであるSQL文に、2つ目のSQLを追加

して、任意のSQLを実行させる

1つのSQLのパラメータ指定に、本来指定で

きないパラメータを指定させることによ

り、意図しないデータを取得したり操作し

たりする

Page 45: PHPでセキュリティを真面目に考える

PHPとSQLインジェクション

任意のSQLを挿入できるか?

$sql = 'SELECT * FROM hoge WHERE foo = $foo';

$foo = '; DELETE FROM hoge;';

// ここでSQL実行

Page 46: PHPでセキュリティを真面目に考える

mysql_query … できない

mysqli_query … できない

pg_query … できる

PDOStatement::execute … できない

Page 47: PHPでセキュリティを真面目に考える

問題なSQLインジェクション

例えばSELECT文に穴があってパスワードを

入手できたりとか

例えばDELETE文に穴があって全データ削除

できたりとか

Page 48: PHPでセキュリティを真面目に考える

回避方法

プレースホルダが利用可能な場面では、極力

プレースホルダを使用する

プレースホルダを使えない場面で、なるべく

文字列結合で値を渡さないようにする

どうしても文字列結合で値を渡す必要がある

場合は、各DBMSに対応するエスケープ関数で

適切にエスケープする

Page 49: PHPでセキュリティを真面目に考える

プレースホルダ

$sql = 'SELECT * FROM hoge WHERE foo = ?;'

$stmt = $mysqli->prepare($sql);

$stmt->bind_param('s', $foo);

$stmt->execute();

Page 50: PHPでセキュリティを真面目に考える

エスケープ関数で

$sql = 'SELECT * FROM hoge WHERE foo = %s;'

$new_sql = sprintf($sql, $mysqli-

>real_escape_string($foo));

$mysqli->query($new_sql);

Page 51: PHPでセキュリティを真面目に考える

テーブル名は特に危険

$sql = 'SELECT * FROM %s WHERE foo = 1;'

$new_sql = sprintf($sql, $foo);

$mysqli->query($new_sql);

// テーブル名なので'hoge'という指定はできない

// $foo に "hoge INNER JOIN …"とか入ると…?

Page 52: PHPでセキュリティを真面目に考える

DBMSと文字コード

不正な文字コードを入れることによって変

なことをさせる攻撃はDBMSにも存在する

mysqlはUTF-8が3byteまでしか入らない(5.5

で対応済)

Page 53: PHPでセキュリティを真面目に考える

MySQLのUTF-8

𣗄 や 𣖔 といった文字が入らない

入れようとするとwarningになるが、空として入る

(errorにはならない)

例えばPHP側で入力チェックをして正常に通過して

も、MySQL側には空文字として入ってしまう、という

ことになる

文字チェックはDB側で行うことが必要

Page 54: PHPでセキュリティを真面目に考える

SQLインジェクションは 大規模な漏洩事件に 繋がりやすい

Page 55: PHPでセキュリティを真面目に考える

PHPは関係ないので概要だけ

Page 56: PHPでセキュリティを真面目に考える

ケータイサイトを馬鹿にするな

基本的には普通のサイトと同じ

ケータイからソースが見えなくてもURLが

見えなくても、実際には同じ

PCサイトと同じレベルのチェックが必要

PCサイトより大変な部分も多い

特に最近はJavaScriptも使える

Page 57: PHPでセキュリティを真面目に考える

IPアドレスで 制限しておけば

余裕だぜー

いや他にも 脆弱性は あるし…

しかもそのIPアドレスリストちゃんと更新してる?

Page 58: PHPでセキュリティを真面目に考える

URLからのセッション乗っ取り

Cookieが使えないケータイブラウザでは、

セッションIDをURLにつけてやりとりする

ことが多い

外部サイトに飛ぶと、refererでセッション

IDが漏れる

そのセッションIDで接続すると…

Page 59: PHPでセキュリティを真面目に考える

URLからのセッション乗っ取り:対策

できるだけCookieを使う

セッションの有効期限を短めにする

外部サイトに飛ぶ場合は、必ず1ページ挟み、そこでは

セッションIDは消す

検索エンジンに登録させない・登録させる場合は、

canonical urlを指定する

<link rel="canonical" href="http://example.com"/>

Page 60: PHPでセキュリティを真面目に考える

かんたんログインも怖い

ちょっとのミスで攻撃方法が多数

「限りなく防ぐ」方法は存在するが、「完璧に

防ぐ」方法は存在しない

Cookieが使用可能であれば極力Cookieを使

用すべき

Page 61: PHPでセキュリティを真面目に考える

ちょっとしたミスで

個人情報が

盗まれている

かもしれない

Page 62: PHPでセキュリティを真面目に考える
Page 63: PHPでセキュリティを真面目に考える

既存のものを使うということ

「それなりに」信頼性がある

特によく使われていて頻繁に更新されているもの

ほど、安全性が高い(可能性が高い)

特にフレームワーク、CMSは、基礎的な脆弱性が

起こらないような作りになっていることが多

く、下手に自作するよりは安全なことが多い

Page 64: PHPでセキュリティを真面目に考える

しかし

使い方を間違えれば脆弱性が生まれる

最新のものを使わないと脆弱性が残ってい

る可能性がある

特にCMSは、見た目で何を使っているかわかりや

すいので、バージョンアップを怠ると狙われや

すい

Page 65: PHPでセキュリティを真面目に考える

何が言いたいのか

ライブラリやフレームワークなどは、ちゃんと

メンテされているものであれば、(検証した上

で)積極的に使おう

バージョンアップされている場合は、(検証し

た上で)対応していこう

ライブラリやフレームワークを過度に信用せ

ず、セキュリティチェックは必ず行おう

Page 66: PHPでセキュリティを真面目に考える

CakePHPの securityコンポーネントにも 脆弱性があった 時代がありました

Page 67: PHPでセキュリティを真面目に考える

脆弱性以前の問題

パスワードはちゃんと設定してますか?

CMSやアプリの管理画面のURLはみんな知って

パスワードが簡単だと簡単に入られてしまう

管理画面はIPアドレス制限、BASIC認証などで、

直接見られなくしておいたほうがいい

Page 68: PHPでセキュリティを真面目に考える
Page 69: PHPでセキュリティを真面目に考える

セキュリティに終わりはない

いつ新しい攻撃方法が発見されるかわか

らない

コンピュータの進化によって不可能が可能

になる場合も

暗号とか

Page 70: PHPでセキュリティを真面目に考える

セキュリティ情報を追い続ける

致命的な脆弱性にすぐ対応できるように

→自分のサイトを守るために

→みんなの個人情報を守るために

Page 71: PHPでセキュリティを真面目に考える

今回話せなかった内容

XSS(クロスサイトスクリプティング)

セッション関係

CSRF

PHPと関係ない話

その他いろいろ

Page 72: PHPでセキュリティを真面目に考える

バグと脆弱性の境界

脆弱性の根本はバグ

バグ=脆弱性 ではない

バグのないプログラムのほうが脆弱性が

少ない可能性が高い

テストなどの、バグを減らすための手法も

実践すべき

Page 73: PHPでセキュリティを真面目に考える

バグが出ても…

エラーは画面に表示しない!

display_errors=OFF

開発中はONにしよう

バグがないことが当然だが、最悪の場合のた

MySQLが突然死した時にうっかりパスワードが見

えたりとか

Page 74: PHPでセキュリティを真面目に考える

セキュリティ情報の探し方

php.net

コピーサイトは見ない

JPCERT/CC

技術系ニュースサイト

(slashdot,gihyo,@IT,etc…)

その他個人ブログなど

Page 75: PHPでセキュリティを真面目に考える

とてもいい情報

gihyo.jp「なぜPHPアプリにセキュリティ

ホールが多いのか?」

http://gihyo.jp/dev/serial/01/php-security

IPA「安全なウェブサイトの作り方」

http://www.ipa.go.jp/security/vuln/websecu

rity.html

書籍「体系的に学ぶ 安全なWebアプリケー

ションの作り方」

Page 76: PHPでセキュリティを真面目に考える

でも情報を探すのとか難しい

札幌でー

セキュリティのー

勉強会とかー

ないかなー

Page 77: PHPでセキュリティを真面目に考える

そうだ、せきゅぽろに参加しよう

北海道情報セキュリティ勉強会 (通称:せきゅぽろ) http://secpolo.techtalk.jp/

Page 78: PHPでセキュリティを真面目に考える
Page 79: PHPでセキュリティを真面目に考える

LOCAL PHP部 参加者募集中!

隔月で勉強会をしています

次回は8月予定

特に内容にこだわりはないので、「これを知

りたい」とか教えてくれれば誰かが用意し

てくれるかもしれません

詳しくは「LOCAL PHP部」で検索!