Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

『例えば、PHPを避ける』以降PHPはどれだけ安全になったか

59,187 views

Published on

PHPカンファレンス北海道2016基調講演

Published in: Technology

『例えば、PHPを避ける』以降PHPはどれだけ安全になったか

  1. 1. 『例えば、PHPを避ける』以降PHPはどれだけ 安全になったか 徳丸 浩
  2. 2. アジェンダ • 例えば、PHPを避ける • htmlspecialchars 文字エンコーディングチェックの改善 • register_globalsが非推奨に • マジッククォートが非推奨に • 暗号学的に安全な擬似乱数生成器のサポート • セッションID生成の安全性強化 • ヌルバイト攻撃の防御機能の追加 • PDOのDB接続時の文字エンコーディング指定が可能に • header関数のバグ修正 • 安全なパスワード保存が簡単にできるようになった Copyright © 2016 Hiroshi Tokumaru 2
  3. 3. 徳丸浩の自己紹介 • 経歴 – 1985年 京セラ株式会社入社 – 1995年 京セラコミュニケーションシステム株式会社(KCCS)に出向・転籍 – 2008年 KCCS退職、HASHコンサルティング株式会社設立 • 経験したこと – 京セラ入社当時はCAD、計算幾何学、数値シミュレーションなどを担当 – その後、企業向けパッケージソフトの企画・開発・事業化を担当 – 1999年から、携帯電話向けインフラ、プラットフォームの企画・開発を担当 Webアプリケーションのセキュリティ問題に直面、研究、社内展開、寄稿などを開始 – 2004年にKCCS社内ベンチャーとしてWebアプリケーションセキュリティ事業を立ち上 げ • 現在 – HASHコンサルティング株式会社 代表 http://www.hash-c.co.jp/ – 独立行政法人情報処理推進機構 非常勤研究員 http://www.ipa.go.jp/security/ – 著書「体系的に学ぶ 安全なWebアプリケーションの作り方」(2011年3月) 「徳丸浩のWebセキュリティ教室 」(2015年10月) – 技術士(情報工学部門) Copyright © 2016 Hiroshi Tokumaru 3
  4. 4. 例えば、PHPを避ける Copyright © 2016 Hiroshi Tokumaru 4
  5. 5. Copyright © 2016 Hiroshi Tokumaru 5 例えば、PHPを避ける
  6. 6. 現在のセキュアプログラミング講座 6 register globalsとナルバイト攻撃が問題??? https://www.ipa.go.jp/security/awareness/vendor/programmingv2/contents/003.html より引用
  7. 7. PHPの何が問題だったか、本当に問題だったか? • セキュアプログラミング講座の改訂は2007年6月 • その時点で、PHPは本当に避けるべき存在だった か? • 当時の最新版はPHP 5.2.3 (2007/5/31) • その後、PHPはどの程度の安全になったか? • 下記について調査 – PHPの安全でない機能の削除 – PHPの安全性を高める機能の追加 Copyright © 2016 Hiroshi Tokumaru 7
  8. 8. htmlspecialchars 文字エンコーディング チェックの改善(PHP5.2.5 2007/11/8) Copyright © 2016 Hiroshi Tokumaru 8
  9. 9. htmlspecialcharsの文字コードチェックの変遷 • PHP4.1.0 (2001/12/10) htmlspecialcharsに第3引数追加。ほとんど何もして いないに等しい文字エンコーディングチェック • PHP-5.2.5 (2007/11/8) 文字エンコーディングのチェックを強化…したけど 抜けがたくさん • PHP-5.2.12 (2009/12/17) moriyoshiの神対応による厳格なチェックに • PHP-5.4.0 (2012/3/1) 第3引数のデフォルトが UTF-8 に変更 Copyright © 2016 Hiroshi Tokumaru 9
  10. 10. そこそこ安全なはずのスクリプト Copyright © 2016 Hiroshi Tokumaru 10 <?php header('Content-Type: text/html; charset=Shift_JIS'); $p1 = @$_GET['p1']; $p2 = @$_GET['p2']; ?><body><form> <input name=p1 value="<?php echo htmlspecialchars($p1, ENT_QUOTES, 'Shift_JIS'); ?>"><BR> <input name=p2 value="<?php echo htmlspecialchars($p2, ENT_QUOTES, 'Shift_JIS'); ?>"><BR> <input type="submit" value="更新"> </form></body>
  11. 11. 半端な先行バイトによるXSS • 半端な先行バイトによるXSSが発生する条件は、 以下のいずれかを満たす場合 – htmlspecialcharsの第3引数を指定していない – PHPの5.2.11以前あるいはPHP5.3.1以前を使用 • 対策としては、以下の両方を行う – PHPの最新版を使う – htmlspecialcharsの第3引数を指定する Copyright © 2010-2014 HASH Consulting Corp. 11 <input name=p1 value="・><BR> <input name=p2 value=" onmouseover=alert(document.cookie)//"><BR> 閉じる引用符が食われた状態 ここで最初の属性値がようやく終了 第二の属性値がイベントハンドラに
  12. 12. register_globalsが非推奨に (PHP-5.3.0 2009/6/30) Copyright © 2016 Hiroshi Tokumaru 12
  13. 13. register_globals=On の危険な例 session_start(); if (isset($_SESSION['user'])) { $islogin = TRUE; } Copyright © 2016 Hiroshi Tokumaru 13
  14. 14. 履歴 • PHP-4.2.0 (2002/4/22) register_globalsがデフォルトで off になる • PHP-5.3.0 (2009/6/30) register_globalsを有効にすると警告エラーになる • PHP-5.4.0 (2012/3/1) register_globalsが廃止される Copyright © 2016 Hiroshi Tokumaru 14
  15. 15. マジッククォートが非推奨に (PHP-5.3.0 2009/6/30) Copyright © 2016 Hiroshi Tokumaru 15
  16. 16. マジッククォートとは何か? • 入力値($_GET、$_POST、$_COOKIE)を予めエスケー プしておく設定 – ' → ' → • SQLインジェクション対策の自動化のために導入さ れた • PHP-5.3.0 (2009/6/30) マジッククォートを有効にすると警告エラーになる • PHP-5.4.0 (2012/3/1) マジッククォートが廃止される Copyright © 2016 Hiroshi Tokumaru 16
  17. 17. マジッククォートはなぜダメだったか? • 不便 – システムが勝手にエスケープするので多重エスケープの原因になる – エスケープが不要な場合アンエスケープの必要があり、不便であり、 脆弱性の要因にもなる • 対策として不十分(文字エンコーディングを考慮しないため …PDOの項参照) • 徳丸の意見 – マジッククォートは入力時にエスケープ処理を自動的行う仕組みだ が、エスケープ処理は文字列を使う時に都度すべきという考え方が 一般化した – マジッククォートはMySQLに特化したエスケープ方式であり、かつ MySQLのオプションや文字エンコーディングを考慮しない不完全な エスケープだった Copyright © 2016 Hiroshi Tokumaru 17
  18. 18. デモメモ: ここでphp.iniを編集して、 register_globalsとmagic_quotes_gpcを オフにしておく Copyright © 2016 Hiroshi Tokumaru 18
  19. 19. 暗号学的に安全な擬似乱数生成器の サポート(PHP-5.3.0 2009/6/30) Copyright © 2016 Hiroshi Tokumaru 19
  20. 20. PHPにおける乱数の状況 • PHPにおける乱数の状況は酷い…下記が用いられる – rand() – mt_rand() – uniqid() • 上記はいずれも暗号学的に安全でない – 過去の乱数列から推測可能性があるということ • PHP-5.3.0から下記がサポートされる – openssl_random_pseudo_bytes() • PHP-7.0.0から下記がサポートされる – random_bytes() – random_int() Copyright © 2016 Hiroshi Tokumaru 20
  21. 21. セッションID生成の安全性強化 (PHP-5.3.2 2010/3/4) Copyright © 2016 Hiroshi Tokumaru 21
  22. 22. 22体系的に学ぶ 安全なWebアプリケーションの作り方 P162、163より引用 PHPはデフォルト設定では以下の組み合わせにMD5ハッシュ関数を通す方法でセッ ションIDを生成しています。  リモートIP アドレス  現在時刻  乱数(暗号論的擬似乱数生成系ではない) これは、図4-51で示したありがちなセッションIDの生成方法に該当します。ロジックの 複雑性が高いため解読方法が判明しているわけではありませんが、理論的には安全性 が保証されていない設計ということになります。
  23. 23. 23http://dsas.blog.klab.org/archives/52136166.html より引用
  24. 24. セッションIDの強化の歴史 • PHP-5.3.2 (2010/3/4) セッションIDの生成方法を複雑化したが不完全 • PHP-5.4.0 (2012/3/1) セッションIDのシードに安全な乱数を使うように • PHP-5.4未満の場合は下記を設定するとよい Copyright © 2016 Hiroshi Tokumaru 24 [Session] ;; entropy_file は Windowsでは設定不要 ;; PHP-5.4以降では下記がデフォルトに session.entropy_file = /dev/urandom session.entropy_length = 32
  25. 25. ヌルバイト攻撃の防御機能の追加 (PHP-5.3.4 2010/12/9) Copyright © 2016 Hiroshi Tokumaru 25
  26. 26. ヌルバイト攻撃はディレクトリトラバーサル等と併用する 26https://www.ipa.go.jp/security/vuln/websecurity.html より引用
  27. 27. ディレクトリトラバーサルとヌルバイト攻撃 • 以下のPHPスクリプト $fp = fopen('./data/' . $_GET['file'] . '.txt', 'r'); … • file=../../../../../etc/passwd%00 とすると ファイル名は以下となる。[nul]は値0の文字 ./data/../../../../../etc/passwd[nul].txt カレントディレクトリが /var/www/html とすると /var/www/html/../../../../../etc/passwd[nul].txt ↓ 正規化 ([nul]以降は無視される) /etc/passwd • Unix / Linux / WindowsのAPIでは通常ヌルバイトを 文字列の終端記号として用いているため Copyright © 2016 HASH Consulting Corp. 27
  28. 28. ディレクトリトラバーサルの影響と対策 • 影響 – 任意のファイルの読み出し – 任意のファイルに任意内容が書き込みできる場合も – PHPスクリプト等を書き込みできれば、任意スクリプト を外部から自由に実行できる場合も • 対策 – ファイル名には basename()関数を通してから使う $file = basename($_GET['file']); – できるだけ新しいPHPを使う • PHP5.3.4以降ではヌルバイト攻撃対策がされている Copyright © 2016 HASH Consulting Corp. 28
  29. 29. PHP 5.3.4におけるヌルバイト攻撃対策 • ファイル名等にヌルバイトが混入している場合、エ ラーとして処理を打ち切る Copyright © 2016 HASH Consulting Corp. 29 $ cat nullbyte.php <?php $rtn = readfile("../../../../etc/passwd0.txt"); var_dump($rtn); $ php-5.3.3 nullbyte.php root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/bin/sh 【中略】 int(1415) $ php-5.3.4 nullbyte.php bool(false)
  30. 30. phpMyAdmin3.5.8に存在した正規表現インジェクション • テーブル名のプリフィックスを変更する処理に存在 Copyright © 2016 HASH Consulting Corp. 30 // $from_prefix, $to_prefix, $currentは外部から操作可能 $newtablename = preg_replace("/^" . $from_prefix . "/", $to_prefix, $current);
  31. 31. 攻撃ができる理由 Copyright © 2016 HASH Consulting Corp. 31 case 'replace_prefix_tbl': $current = $selected[$i]; $newtablename = preg_replace("/^" . $from_prefix . "/", $to_prefix, $current); preg_replace("/^/e0/", "phpinfo();", "test"); preg_replace("/^/e", "phpinfo();", "test"); $from_pref = "/e0" PHP5.4.3以前では、0以降は無視される
  32. 32. /e 修飾子… 32http://www.php.net/manual/ja/reference.pcre.pattern.modifiers.php
  33. 33. 脆弱性が混入した要因 • preg_replaceに渡す正規表現をエスケープしていな かった – 最低限、/ をエスケープする必要がある…理論的には • えーっと、preg_quoteって、マルチバイト対応だっ け? – Shift_JIS以外では問題ない? • 外部からの値を用いて正規表現を組み立てるべきで はない Copyright © 2016 HASH Consulting Corp. 33 preg_replace(“/^” . $from_prefix . “/”, … ↓ reg_replace("/^" . preg_quote($from_prefix, '/') . "/", …
  34. 34. PDOのDB接続時の文字エンコーディング 指定が可能に(PHP-5.3.6 2011/3/17) Copyright © 2016 Hiroshi Tokumaru 34
  35. 35. 【文字コードの問題1】 5C問題によるSQLインジェクション • 5C問題とは – Shift_JIS文字の2バイト目に0x5Cが来る文字に起因する問 題 ソ、表、能、欺、申、暴、十 … など出現頻度の高い文字 が多い – 0x5CがASCIIではバックスラッシュであり、ISO-8859-1な ど1バイト文字と解釈された場合、日本語の1バイトが バックスラッシュとして取り扱われる – 一貫して1バイト文字として取り扱われれば脆弱性になら ないが、1バイト文字として取り扱われる場合と、 Shift_JISとして取り扱われる場合が混在すると脆弱性が発 生する Copyright © 2014 HASH Consulting Corp. 35
  36. 36. ソースコード(要点のみ) <?php header('Content-Type: text/html; charset=Shift_JIS'); $key = @$_GET['name']; if (! mb_check_encoding($key, 'Shift_JIS')) { die('文字エンコーディングが不正です'); } // MySQLに接続(PDO) $dbh = new PDO('mysql:host=localhost;dbname=books;charset=sjis', 'phpcon', 'pass1'); // Shift_JISを指定 $dbh->query("SET NAMES sjis"); // プレースホルダによるSQLインジェクション対策 $sth = $dbh->prepare("SELECT * FROM books WHERE author=?"); $sth->setFetchMode(PDO::FETCH_NUM); // バインドとクエリ実行 $sth->execute(array($key)); ?> Copyright © 2014 HASH Consulting Corp. 36
  37. 37. 5C問題によるSQLインジェクションの説明 Copyright © 2014 HASH Consulting Corp. 37
  38. 38. SQLインジェクション対策はプレースホルダで • プレースホルダとは SELECT * FROM books WHERE id=? • 静的プレースホルダと動的プレースホルダ – 静的: サーバー側で値をバインドする(エスケープは必要 ない) – 動的: 呼び出し側で値をエスケープしてバインドする • 接続時に文字エンコーディングを指定する $db = new PDO('mysql:host=myhost;dbname=mydb;charset=utf8', DBUSER, DBPASS); – SET NAMES utf8 はやめましょう • 列の型を意識する Copyright © 2012-2015 HASH Consulting Corp. 38
  39. 39. サンプルコード $db = new PDO('mysql:host=myhost;dbname=mydb;charset=utf8', DBUSER, DBPASS); // エミュレーションモードOFF = 静的プレースホルダ $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); // エラー時に例外を発生させる $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // プレースホルダを使ってSQLを準備 $prepare = $db->prepare( 'SELECT * FROM example WHERE id = :id and language = :lang'); // 型を指定してbind $prepare->bindValue(':id', (int) $id, PDO::PARAM_INT); $prepare->bindValue(':lang', $str, PDO::PARAM_STR); $prepare->execute(); Copyright © 2012-2015 HASH Consulting Corp. 39
  40. 40. header関数のバグ修正 (PHP-5.4.0 2012/3/1) Copyright © 2016 Hiroshi Tokumaru 40
  41. 41. HTTPヘッダインジェクション 41安全なウェブサイトの作り方改訂第7版より引用
  42. 42. このサンプルプログラムでどこまで悪用できるか? Copyright © 2016 Hiroshi Tokumaru 42 <?php header('Location: ' . $_GET['url']);
  43. 43. ヘッダインジェクションによるXSSフィルタ回避 Copyright © 2016 Hiroshi Tokumaru 43 <?php $cookie = $_GET['cookie']; $txt = $_GET['txt']; header('Content-Type: text/html; charset="UTF-8"'); header('Set-Cookie: A=' . $cookie); ?><!DOCTYPE html> <body><?php echo "Cookie A=" . htmlspecialchars($_COOKIE['A']) ; ?> <?php echo $txt; // XSS脆弱性あり ?></body> X-XSS-Protection: 0 ヘッダを追加して、XSSフィルタを無効にしたい…
  44. 44. header関数改修の歴史 • PHP 5.1.2 – 改行のチェックが追加される – %0d(キャリッジリターン)のチェックが漏れていた • PHP 5.3.11 および PHP 5.4.0 – キャリッジリターンのチェックが追加される – 継続行(下図)については許容 • PHP 5.4.38 / PHP 5.5.22 / PHP 5.6.6 – 継続行が禁止される Copyright © 2016 Hiroshi Tokumaru 44 Location: http://php.net/ Set-Cookie: PHPSESSID=ABC; ↑空白またはタブ
  45. 45. Linuxディストリビューションの対応 Copyright © 2016 Hiroshi Tokumaru 45 ※CentOS5 ~ 7 / Ubuntu 14.04以前はパッチが出ていない
  46. 46. 安全なパスワード保存が簡単にできるよ うになった(PHP-5.5.0 2013/6/20) Copyright © 2016 Hiroshi Tokumaru 46
  47. 47. password_hash 関数 (PHP5.5から) http://php.net/manual/ja/function.password-hash.php より引用 <?php echo password_hash('rasmuslerdorf’, PASSWORD_DEFAULT); 【結果】 $2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a 47
  48. 48. まとめ • 『例えば、PHPを避ける』の時代は、現実にPHPの 罠はかなりあった – 『避ける』必要はないにしても、気をつけなければ脆弱 性の原因に… • 2016年現在で、罠はかなり解消されつつある • 特に以下は重要 – Htmlspecialcharsの文字エンコーディングチェック – PDOのDB接続時の文字エンコーディング指定 • できるだけ新しいバージョンのPHPを使う • でも、もっと大切なことは、最新のパッチのあたっ たPHPを使うこと • PHPを使って、安全で素晴らしいサイト構築を! Copyright © 2016 Hiroshi Tokumaru 48
  49. 49. ご清聴ありがとうございました Copyright © 2016 Hiroshi Tokumaru 49

×