10月3日,
イベント開始前の最終確認するスタッフの皆さん。この後,
本日のイベントの模様は,
オープニング
実行委員長の前島有貴さんより,
その後,
お昼には,
- 12:00~12:30:
『Laravelエキスパート養成読本』 - 12:30~13:00
『PHPはどのように動くのか』 - 15:10~15:40
『実践ドメイン駆動設計』
なお,
廣川類さん「PHPの今とこれから2015」
オープニングの挨拶の後,
今年でPHPは,
PHP7は,
PHPという言語について次のように説明しました。
- 主にWebアプリケーションで使用されるスクリプト言語
- 1995年の誕生以来,
Webと共に成長, 進化
サーバサイドプログラミング言語では8割ほど使われていて,
使用されているPHPのバージョン分布を見るとバージョン5.
バージョン5.
なお,
そして,
- 大幅高速化
- 致命的エラーを例外補足可能
- 古いSAPI,
エクステンションの削除 - ヌル合体演算子
(??) - 結合比較演算子
(<=>) - 戻り値型宣言
- スカラー型宣言
- 匿名クラス
一番大きなポイントは高速化になります。ベンチマークによるとPHP5.
それから,
それから,
PHP7の互換性に関する変更として,
- エクステンション削除:ereg, mysql, msspl
- SAPI削除:22種類から7種類
- ASP
(<%...%>), Script (<script language="php"></script>) の廃止 - newオブジェクトの参照代入廃止
- PHP4形式のコンストラクタ:E_
DEPRECATED - エクステンションは要変更:http://
gophp7. org/ gophp7-ext/
今後の開発は,
- PHP7.
1開発が開始 - PCO
(PHP Cryptography Objects) - JITコンパイラ
PHP7.
PHPの今とこれからが,
徳丸浩さん「今どきのSQLインジェクションの話題総まとめ」
2009年からPHPカンファレンスでトークをしている徳丸浩さんの発表です。SQLインジェクション対策漏れの責任を開発会社に問う判決の話と,
SQLインジェクション対策もれの責任を開発会社に当判決
2009年の資料で安全なアプリケーションの発注要件の話では,
ところが昨年判例が出ました。その判例が家具インテリアECサイト侵入事件です。家具インテリアのECサイトを運営するX社がECサイトをY社に発注してそのサイトから2011年にクレジットカードの情報が漏洩。X社はY社に損害賠償を起こし,
裁判の争点は次のとおりです。
- 特にセキュリティに指示はしてなかった。
- 当初はカード情報を扱っていなかったが,
X社の依頼でカード情報を保持するようになった。 - カード情報は持たないほうがいいとX社が問い合わせた。
- ログが他社から見れるようになっておりそのログにも個人情報が入っていた。
- 管理機能のID/
PASSがadmin/ passwordになっていた。
判断はいろいろ考えられますが,
よって,
徳丸さんの感想は,
こういった判決が出たことで,
PHP入門書のSQLインジェクション脆弱性の状況
PHP入門書のセキュリティの批判をしていると,
そして,
* はじめてのPHPプログラミング
2008年に発行された
function dbescape($sql, array $params)
{
foreach ($params as $param) {
switch (getup($param)) {
case “inteher”:
case “double”:
$replasemment = $param;
break;
case “string”:
// 文字列の場合はエスケープ処理を行う
$replasemment = sprintf(“‘%s’”, sqlite_escape_string($param));
break;
default:
die(“パラメータの方が正しくありません");
}
// SQLを置換し,パラメータを埋め込む
$sql = substr_replace($sql, $replasemment, strpos($sql, “?”), 1);
}
return $sql;
}
しかしこの場合,
SELECT * FROM foo WHERE bar = ? AND base = ?
↑’?’に置き換え
SELECT * FROM foo WHERE bar = ’?’ AND base = ?
↑ ‘AAA’に置き換え
SELECT * FROM foo WHERE bar = ’‘AAA’’ AND base = ?
AAAがリテラル外にはみ出す↑
SQLインジェクション攻撃は次のようになると示しました。
SELECT * FROM foo WHERE bar = ? AND base = ?
↑’?’ぶ置き換え
SELECT * FROM foo WHERE bar = ’?’ AND base = ?
↑ ‘or 1 = 1--’に置き換え
SELECT * FROM foo WHERE bar = ’‘or 1 = 1--’’ AND base = ?
or 1 = 1--がリテラル外にはみ出す↑
ここから得られる教訓はプレースホルダの仕組みを安易に自作すると徳丸さんに怒られることです。十分に考慮して作りましょう。
* よくわかるPHPの教科書
『よくわかるPHPの教科書』
ここでSQLインジェクションを実演してDELETE文で意図しない書き込みの削除ができるところを示しました。エスケープは難しいところがあるため,
また,
他にも,
* 気がつけばプロ並みPHP
『気がつけばプロ並みPHP』
* その他の本はどうなの?
最近はPDOのプレースホルダを使うのが主流になっているため,
また,
- SQLインジェクション対策はPDOのプレースホルダで静的と動的があり静的を使うほうが安全。
- 文字エンコーディングの指定はPDOの5.
3.6以降で接続文字列に文字エンコーディングが指定できるようになったので, これを使う。SET NAMES outfitはやめる。 - PDOの癖としてPDO::PRAM_
INTを指定しても文字列として扱われるため, int型にキャストしたほうがいい。
O/RマッパやSQLジェネレータのSQLインジェクション
次に,
* Rails SQL Injection Examples
Rails SQL Injection Examplesというサイトで脆弱性について言及されています。Railsの話なので言語はRubyになりますが,
例題の実演をして,
また,
SELECT * FROM 成績 ORDER BY (算数+国語)
複雑なものも書けるそうで,
エラーメッセージから情報を取得できますが,
orderメソッドでUNION SELECTから情報漏洩はできるのか。
- ORDER BYのあとでUNIONは使えない
- 複文ではmissing attributeとエラーが出る
といった条件を考慮して列名に別名をつけると,
* Zend FrameworkのSQLインジェクション
Zend FrameworkのSQLインジェクションの説明では,
$select = $db->select()
->from(products)
->order(’name’); //列 nameでソート
orderメソッドで式を書くとそこで式も指定できます。これはまずいのでは?
if (pre_match(‘/\(.*\)/‘, $val)) { // (と)があれば
#val = new Zend_Db_Expr($val); // 式とみなす
}
その時の徳丸さんは,
CVE-2014-4914 (Zend Framework 1.
- orderの引数文字列に(と)がありさえすれば式とみなされエスケープ対象となる。
- 1;攻撃文字列 ?() とかでもOK。
- 公表されたPoCは次のとおり。
order(‘MDS(1); drop table products --')
↓生成されるSQL文
SELECT `products`.* FROM `products` ORDER BY MD5(1); drop table products --
Zend Framework 1.
//1.12.7
if (pre_match(‘/^[\w]*\(.*\)$/‘, $val)) {
#val = new Zend_Db_Expr($val);
}
// 英数字0文字以上に続けて(があり,末尾に)があれば式とみなす
という形になっていました。その時の徳丸さんは,
Zend Framework 1.
order(‘MDS(1); drop table products --')
↓生成されるSQL文
SELECT `products`.* FROM `products` ORDER BY 'MDS(1); drop table products ?' ASC
// order by以降が’で囲まれて識別子となる
新しいPoCでは次のようになります。
order(‘MDS(1); drop table products ?)')
↓生成されるSQL文
SELECT `products`.* FROM `products` ORDER BY MDS(1); drop table products ?) ASC
// 式とみなされる条件を満たし,「そのまま」SQL文に
そして,
//1.12.8
if (pre_match(‘/^[\w]*\([^\]*\)$/‘, $val)) {
#val = new Zend_Db_Expr($val);
}
// 英数字0文字以上に続けて(があり,途中は)以外が続き,
// 末尾に)があれば式とみなす
なんとなく攻撃は難しくなっているけど,
* JSON SQLインジェクション
SQL::makerというクエリビルダーがあります。プレースホルダを作ってバインド値も作ってくれて値をリストで渡すとIN演算子に勝手にしてくれたり便利なものですが,
もし演算子の部分がいじれてしまうと,
SQL::makerをPHP版に移植した人がいたので,
変数の値がyamadaの場合は次のようになります。
SQL文: SELECT * FROM `users` WHERE (`name` = ?)
また,
SQL文: SELECT * FROM `users` WHERE (`name` KEY ?)
PHPはGET/
http://example.jp/query.php?user_name[key]=value
となり,
PerlよりPHPのほうが簡単に攻撃ができてしまうので注意が必要です。対策としてはSQL::maker側はstaticモードを追加して,
* Drupageddon (CVE-2014-3704)
Drupageddon (CVE-2014-3704) は,
Drupalは3大CMSの一つで,
この脆弱性は10月15日に発表された直後に攻撃が開始され10月15日午後11時 (日本時間16日午前8時)
通常の要求は次のような形です。
name=admin&pass=xxxxxx
これは,
SELECT * FROM users WHERE name = ‘admin’ AND status = 1
このnameを配列で指定しています。
name[]=user1&name[]=user2&pass=xxxxxx
SELECT * FROM users WHERE name = ‘user1’, ‘user2' AND status = 1
この時点で問題があります。JSON SQLインジェクションにもあったように,
name[id1]=user1&name[id2]=user2
となり,
SELECT * FROM users WHERE name = :name_id1, :name_id2 AND status = 1
そして,
name[1 xxxx]==user1&name[2]=user2
となります。プレースホルダに空白が含まれてしまい,
SELECT * FROM users WHERE name = :name_1 xxxx, :name_2 AND status = 1
すでにSQLインジェクションは起こっていますが,
name[2 xxxx]=&name[2]=user2
SELECT * FROM users WHERE name = :name_2 xxxx, :name_2 AND status = 1
プレースホルダは:name_
このことを脆弱性のあるバージョンで実演しました。実演したのは次のような10秒待つSQLインジェクションです。
name[2 ;SELECT sleep(10) ? ]=&name[2]=user2
さらに,
* 問題点まとめ
一連の問題点をまとめると,
- Zend Frameworkは,
orderメソッドの仕様が明確でなかった。 - SQL::Makerは,
キーを外部から入力される想定をしていなかった。 - Drupalでは,
配列は想定していたが, 連想配列は想定していなかった (7. 36で配列を弾くようにバリテーションをするようになった)。
まとめ
最後に徳丸さんは,
- SQLインジェクション対策もれの責任を開発会社に当判決が出た。
- PHP入門書のSQLインジェクションは解消されつつありますが,
まだまだ他の脆弱性がある。 - SQLジェネレータの実装に起因するSQLジェネレータ脆弱性は仕様の考慮漏れやバリテーション不足。
- SQLジェネレータ利用者側の注意ライブラリのマニュアルをよく読みバリテーションは普通にやっておこう。