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.

ウェブセキュリティの常識

20,224 views

Published on

セキュリティ・ミニキャンプ in 近畿 2017(神戸)における講演です
http://www.security-camp.org/minicamp/kobe2017.html

Published in: Technology
  • Be the first to comment

ウェブセキュリティの常識

  1. 1. Webアプリセキュリティの常識 EGセキュアソリューションズ株式会社 徳丸浩
  2. 2. アジェンダ • Webサイト攻撃のトレンドと対処法 • 攻撃の典型例 – SQLインジェクション攻撃 – CSRF – クロスサイトスクリプティング(XSS) – クリックジャッキング • 今時のウェブサイトの守り方 2
  3. 3. 徳丸浩の自己紹介 • 経歴 – 1985年 京セラ株式会社入社 – 1995年 京セラコミュニケーションシステム株式会社(KCCS)に出向・転籍 – 2008年 KCCS退職、HASHコンサルティング株式会社(現社名:EGセキュアソリューショ ンズ株式会社)設立 • 経験したこと – 京セラ入社当時はCAD、計算幾何学、数値シミュレーションなどを担当 – その後、企業向けパッケージソフトの企画・開発・事業化を担当 – 1999年から、携帯電話向けインフラ、プラットフォームの企画・開発を担当 Webアプリケーションのセキュリティ問題に直面、研究、社内展開、寄稿などを開始 – 2004年にKCCS社内ベンチャーとしてWebアプリケーションセキュリティ事業を立上げ • 現在 – EGセキュアソリューションズ株式会社 代表 https://www.eg-secure.co.jp/ – 独立行政法人情報処理推進機構 非常勤研究員 https://www.ipa.go.jp/security/ – 著書「体系的に学ぶ 安全なWebアプリケーションの作り方」(2011年3月) 「徳丸浩のWebセキュリティ教室 」(2015年10月) – 技術士(情報工学部門) 3
  4. 4. Webサイト攻撃のトレンドと対処法 4
  5. 5. Webサイトに対する侵入事件のトレンド • 2000年:各省庁を狙った改ざん事件 – 「ファイアウォールが導入されていなかった」という報道から、FW導入の きっかけに • 2005年:カカクコム、ワコールなどに対するSQLインジェクション攻撃 (理論的可能性から実際の脅威に) • 2008年:SQLインジェクション攻撃が急増 • 2009年~2010年:Gumblar騒動 • 2011年:PSN事件、ソニー関連会社への攻撃、Lizamoon攻撃(SQLイン ジェクション) • 2012年:Anonymous、国際情勢がらみの攻撃 • 2013年:パスワードリスト攻撃など不正ログインの多発 • 2014年:Heartbleed、Strutsの脆弱性等 • 2015年:Joomlaの脆弱性CVE-2015-8562に対する攻撃 • 2017年:WordPress REST APIの脆弱性、Struts2 S2-045脆弱性に対する 攻撃 5
  6. 6. セキュリティはイタチごっこと言うけれど • 2000年頃の侵入事件は、以下が多いと推測 – ローカルネットワーク向けのポート(RPC等)に対する攻撃 – 管理用 telnet / ftp / ssh に対する辞書攻撃 – Apache や sendmail の脆弱性悪用 • 上記が対策された後に、SQLインジェクションの全盛期 (2005年~2010年頃) • SQLインジェクションが対策されてくると下記が台頭 – フレームワーク(Struts2、Ruby on Rails等)の脆弱性を狙った攻撃 – 著名アプリケーション(WordPress等)の脆弱性を狙った攻撃 – 管理端末のマルウェア感染(端末脆弱性や管理者の不注意) (いわゆるガンブラー、標的型攻撃) – ユーザーパスワードに対する攻撃 (フィッシング、パスワードリスト攻撃) 6
  7. 7. SQLインジェクション攻撃 7
  8. 8. カスタマイズした画面にSQLインジェクション(正常系) 8 この画面はデモ 用に作成したも のです
  9. 9. SQLインジェクションで情報を盗む方法 • UNION SELECTを使う • エラーメッセージを使う • なんらかの1ビットの情報を積み重ねる(Blind SQLi) – 表示上のなんらかの差異 – エラーの有無 – ステータスコードの違い(200 or 500など) – 更新できるか否か – 時間差 (Time-base SQL Injection) 9
  10. 10. information_schema 10
  11. 11. カスタマイズした画面にSQLインジェクション(検証例) 11 $state = $_POST['state']; $city = $_POST['city']; $town = $_POST['town']; $db = mysql_connect(DB_SERVER, DB_USER, DB_PASSWORD); mysql_select_db(DB_NAME, $db); $r = mysql_query("SELECT * FROM mtb_zip WHERE state = '$state' AND city LIKE '$city%' AND town LIKE '$town%' LIMIT 100"); 続きはデモで
  12. 12. 日本で一番売れているPHP教科書のサンプル 12 // ここまでで、認証済みであるこの検査が済んでいる $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()); } ここにSQLインジェクション しかし、DELETE FROM 文なので表示はない たにぐちまこと、「よく分かるPHPの教科書」 P272より引用
  13. 13. エスケープしているのになぜSQLインジェクション? $id = ’88-1’; で説明。これはエスケープ後も 88-1 $sql = sprintf('SELECT * FROM posts WHERE id=%d', mysql_real_escape_string($id)); ↓ 生成されるSQL文は、88-1が%dの整数化で88になるので SELECT * FROM posts WHERE id=88 mysql_query(‘DELETE FROM posts WHERE id=’ . mysql_real_escape_string($id)); ↓ 生成されるSQL文は、エスケープ後も 88-1 のままなので DELETE FROM posts WHERE id=88-1 ※チェックはid=88で、削除されるのはid=88-1 すなわち、87が削除される 13
  14. 14. エラーメッセージから情報窃取 • MySQLはエラーメッセージの中にリテラルの情報を含めな いものが多いが、例外としてextractvalue関数がある mysql> select extractvalue('<a><b>xss</b></a>', '/a/b'); +-------------------------------------------+ | extractvalue('<a><b>xss</b></a>', '/a/b') | ← 正常系 +-------------------------------------------+ | xss | +-------------------------------------------+ mysql> SELECT extractvalue('<a><b>xss</b></a>', '/$this is a pen'); ERROR 1105 (HY000): XPATH syntax error: '$this is a pen' • 副問い合わせにより、extravalueにわざとエラーのあるクエ リを用いて情報窃取 mysql> SELECT extractvalue('',concat('/$',(SELECT cardnumber FROM eccube_db.dtb_customer_card LIMIT 1 OFFSET 0) )); General error: 1105 XPATH syntax error: '$1234567890123456' 14
  15. 15. SQL文のエラーが起こるか否かで情報を盗む • SQLインジェクションにより実行されるSQL文の例 DELETE FROM posts WHERE id=18-(SELECT id FROM members WHERE id LIKE char(49) ESCAPE IF(SUBSTR((SELECT email FROM members LIMIT 1,1),1,1)>='M', 'a', 'ab'))) • WHERE句の中 18-(SELECT … WHERE …) • 中のWHERE句は LIKE 述語にESCAPE句がある • ESCAPE句はIF関数により、membersの1行目の1文字目が ’M’以上の場合’a’、それ以外の場合’ab’ • SQL文の文法上、ESCAPE句は1文字以外だとエラー • この結果を繰り返すことによって、対象文字列を絞り込む →ブラインドSQLインジェクション 15
  16. 16. SQLインジェクション対策はプレースホルダで • プレースホルダとは SELECT * FROM books WHERE id=? • 静的プレースホルダと動的プレースホルダ – 静的: サーバー側で値をバインドする(エスケープは必要 ない) – 動的: 呼び出し側で値をエスケープしてバインドする • 接続時に文字エンコーディングを指定する $db = new PDO('mysql:host=myhost;dbname=mydb;charset=utf8', DBUSER, DBPASS); • 列の型を意識する 16
  17. 17. サンプルコード(PHP5.5.21 以降) // エミュレーションモードOFF = 静的プレースホルダ $opt = array(PDO::ATTR_EMULATE_PREPARES => false, // 「複文」を禁止する (PHP 5.5.21 / PHP 5.65 以降で有効) PDO::MYSQL_ATTR_MULTI_STATEMENTS => false); // 文字エンコーディング指定は PHP 5.3.7 以降 $db = new PDO('mysql:host=myhost;dbname=mydb;charset=utf8', DBUSER, DBPASS, $opt); // プレースホルダを使ってSQLを準備 $prepare = $db->prepare( 'SELECT * FROM example WHERE id = :id and language = :lang'); // 型を指定してbind (キャストはPDOのバグ対策) $prepare->bindValue(':id', (int) $int, PDO::PARAM_INT); $prepare->bindValue(':lang', $str, PDO::PARAM_STR); $prepare->execute(); 17
  18. 18. クロスサイト・リクエストフォージェリ(CSRF) 18
  19. 19. 横浜市のCSRF悪用の犯行予告手口(推測) 19http://d.hatena.ne.jp/Kango/20121008/1349660951 より許諾を得て引用
  20. 20. 日本で一番売れているPHP教科書のサンプル 005: if (isset($_SESSION['id']) && $_SESSION['time'] + 3600 > time()) { 006: // ログインしている 省略 014: } else { 015: // ログインしていない 016: header('Location: login.php'); exit(); 017: } 018: 019: // 投稿を記録する 020: if (!empty($_POST)) { 021: if ($_POST['message'] != '') { 022: $sql = sprintf('INSERT INTO posts SET member_id=%d, message="%s", reply_post_id=%d, created=NOW()', 023: mysql_real_escape_string($member['id']), 024: mysql_real_escape_string($_POST['message']), 025: mysql_real_escape_string($_POST['reply_post_id']) 026: ); 027: mysql_query($sql) or die(mysql_error()); 028: 029: header('Location: index.php'); exit(); 030: } 031: } 20 CSRF脆弱性 対策していない 続きはデモで たにぐちまこと著「よくわかるPHPの教科書」より引用
  21. 21. CSRFによる成りすまし投稿 21 ③被害者のブラウザ経由 で掲示板に書き込み 掲示板の書き込みログは 被害者のIPアドレス
  22. 22. CSRF対策の方法は? • 色々な対策が知られている • トークンによるもの • 再認証 • Refererのチェック • Captcha • … • 実際は、トークン一択と考えて良い 22
  23. 23. トークンはどうやって生成する? • ワンタイムトークンである必要はない – セッション毎に固定で良い – いわゆるワンタイムトークンだと処理が複雑になる • セッション毎に一度「安全な乱数生成器」で生成する – openssl_random_pseud_bytes() ← PHP5.3以降 – random_bytes() ← PHP 7以降 オススメ – /dev/urandom から読み込み (UNIX/Linux) $rand = file_get_contents(‘/dev/urandom’, false, NULL, 0, 24); $token = bin2hex($rand); • type=hiddenなinputとセッションの両方に書いておいて、両 者を比較する。違っていたらエラー 23
  24. 24. クロスサイト・スクリプティング(XSS) 24
  25. 25. XSSはなぜ危険か? • XSSは、 – 利用者(被害者)のブラウザ上で – 攻撃対象のドメイン(オリジン)で – 攻撃者が自由にJavaScriptを実行できる • これって、ウイルス? – ウイルスではないが、結果としてウイルスと同じような被害 – XSSを悪用したウイルス(ワーム)はいくつかある • ブラウザを乗っ取られたのと同じ – 影響範囲はXSS脆弱性のあるページと同じドメイン(オリジン) – 同一オリジン上はすべてのページが影響を受ける ※オリジン=ホスト名+スキーム+ポート番号 25
  26. 26. XSSのデモ • 先ほどのCSRF対策済みの掲示板で、なりすまし書 き込みをやってみよう • 実行するスクリプトは下記のもの 26 <script> var token = document.getElementsByName('token')[0].value; var req = new XMLHttpRequest(); req.open('POST', 'index.php'); req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); data = 'message=ぼくはまちちゃん!こんにちはこんにちは!!&token=‘ + token; req.send(data); </script>
  27. 27. XSSの対策 • 文脈に応じてHTMLエスケープ – エスケープするタイミングは表示の直前 – htmlspecialcharsの引数に注意 • 第2引数は、文脈により変えるか、ENT_QUOTES固定 • 第3引数はPHP内部の文字エンコーディングを指定 PHP5.3までのデフォルトは ISO-8859-1 PHP5.4, 5.5のデフォルトは UTF-8 PHP5.6からはデフォルトとして default_charset • 属性値はダブルクオートで囲む • レスポンスヘッダで文字エンコーディングを指定 – header('Content-Type: text/html; charset=UTF-8'); • JavaScriptの動的生成を避ける – HTML上に値を書いてJavaScriptから参照 27
  28. 28. クリックジャッキング 28
  29. 29. クリックジャッキング攻撃 • 機能を勝手に実行させられるという点でCSRFと類似 • ターゲットの画面をiframe上で「透明に」表示する • その下にダミーの画面を表示させる。ユーザにはダミーの画 面が透けて見える • 利用者がダミーの画面上のボタンを押すと、実際には全面の ターゲット画面のボタンが押される 29 本当の画面(前面、透明) ダミーの画面(後面)
  30. 30. CSRF/クリックジャッキングの対策 • CSRF対策はトークンによる方法に統一しよう – 「ワンタイムトークン」である必要はない • クリックジャッキングされると困るページには、X-FRAME-OPTIONSヘッダを指 定する(徳丸本P63) – frame/iframeを禁止して良い場合 header('X-FRAME-OPTIONS', 'DENY'); – frame/iframeを禁止できないが単一ホストの場合 header('X-FRAME-OPTIONS', 'SAMEORIGIN'); • CSRF対策のトークン発行しているページが対象となる 30 入力画面 メールアドレス foo@pexample.jp 変更 実行画面 メールアドレスアドレスを変更 しました header('X-FRAME-OPTIONS', 'DENY'); … <input type="hidden" name="token" value="a89daf89af0…"> セッション等に保存したtokeとhiddenの token値を比較)
  31. 31. 今時のウェブサイトの守り方 31
  32. 32. 安全なWebサイトの構築方法 • ログインを守る – ログインの入り口は外部に公開しない – パスワード管理の徹底 • プラットフォームの脆弱性に対処する – サイトのライフサイクル管理を計画する – パッチ適用容易性を確保する • アプリケーションの脆弱性に対処する – 脆弱性が「ないこと」をベンダーに要求 – 脆弱性検査 32
  33. 33. CMSやDBの管理コンソール(ログイン) • CMSやDBの管理コンソールが外部に公開されてい る状況は非常によろしくない • どうしても外部に公開しないと行けない場合は、以 下のいずれか、あるいは両方を実施 – IPアドレスを制限 – BASIC認証による制限 • アプリ側にログイン機能があるからと言って安心し ないこと – 保護が十分でない場合がある – アプリの脆弱性をつかれる場合がある 33
  34. 34. パスワード! パスワード! パスワード! • 極論するとユーザ名は"admin"でもよい – adminだと自動攻撃に狙われるのでウザいということはあ る • とにかくパスワードをちゃんとすることが重要 – 8文字以上 – 英数字を混ぜる – 辞書に載っている単独はだめ – できればランダム文字列 – 他所で使ってないもの 【重要】 – 管理者が複数存在する場合は、管理者毎にユーザーを作 成する 34
  35. 35. ソフトウェアのバージョンアップまたはパッチ適用 • 脆弱性対処は、バージョンアップまたはパッチ適用 が基本 – 自らビルド等している場合はバージョンアップが楽な場 合が多い – CentOS、Debian、Ubuntu等のディストリビューション のパッケージを導入している場合はパッチ適用 • バージョンアップするとサイトが動かなくなる…な んて心配をしないで、とにかくバージョンアップす ること • 自力でトラブル対処ができないソフトは導入しない こと 35
  36. 36. どんなサーバーを借りたらよいか? セキュリティ対策 IaaS/VPS PaaS/レンサバ SaaS WAF 利用者 (事業者) - PHP/Apache 利用者 事業者 事業者 CMS 利用者 利用者 事業者 プラグイン 利用者 利用者 事業者 カスタマイズ部分 利用者 利用者 - パスワード 利用者 利用者 利用者 36 • IaaSやVPSは利用者が「全て」の対応をする必要がある • PaaSやレンタルサーバーはインフラの面倒は見てくれる • SaaSの場合、パスワードさえしっかり管理すれば
  37. 37. 先の図は情報処理安全確保支援士試験に出題されました 37 平成29年度春期情報処理安全確保支援士試験 午前Ⅱ 問8 より引用
  38. 38. Webアプリケーションの有名な脆弱性 • SQLインジェクション • クロスサイト・スクリプティング(XSS) • クロスサイト・リクエスト・フォージェリ(CSRF) • … • 脆弱性の種類はたくさんあるが、せめて上記の三種 類は把握しておくこと • Webサイト公開前に脆弱性を修正しておく • カスタムアプリの場合、新規追加・修正がない限り、 頻繁に診断する必要性は薄い • セキュアプログラミングの体制を作る 38
  39. 39. まとめ • Webサイト攻撃のトレンドと対処法 • 攻撃の典型例 – SQLインジェクション攻撃 – CSRF – XSS – クリックジャッキング • 今時のウェブサイトの守り方 – 認証の強化、特にパスワード – 基盤ソフトウェアのパッチ適用 – セキュアプログラミングの体制を作る 39

×