---
title: ウェブアプリケーションセキュリティ超入門
tags:  #security  
author: [徳丸 浩](https://convert.docswell.com/user/ockeghem)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/4V7P8GYV78.jpg?width=480
description: OWASP Nagoya Local Chapter Meeting 1st 講演資料です https://owaspnagoya.connpass.com/event/59813/
published: September 02, 17
canonical: https://convert.docswell.com/s/ockeghem/5M6LNZ-owasp-nagoya20170902
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/4V7P8GYV78.jpg)

ウェブアプリケーションセキュリティ超入門
EG セキュアソリューションズ
徳丸 浩


# Page. 2

![Page Image](https://bcdn.docswell.com/page/L2JVN6GREQ.jpg)

徳丸浩の自己紹介
• 経歴
– 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月)
– 技術士（情報工学部門）
2


# Page. 3

![Page Image](https://bcdn.docswell.com/page/Z5EGKN867L.jpg)

アジェンダ
•
•
•
•
•
•
侵入を受けるウェブサイトとはどういう状況なのか？
入力値の問題
SQLインジェクション
クロスサイト・リクエストフォージェリ(CSRF)
クロスサイト・スクリプティング(XSS)
アップロードの問題
3


# Page. 4

![Page Image](https://bcdn.docswell.com/page/V4JQNQ92JP.jpg)

侵入を受けるウェブサイトとはどういう状況
なのか？
4


# Page. 5

![Page Image](https://bcdn.docswell.com/page/DK74GNXPJ1.jpg)

Webサイトへの侵入経路
• 認証を突破される
– telnet, FTP, SSH等のパスワードを推測される
– FTP等のパスワードがマルウェア経由で漏洩する
• ソフトウェアの脆弱性を悪用される
– 基盤ソフトウェアの脆弱性を悪用される
• Apache, PHP, JRE(Java), Tomcat, …
• 脆弱性は世界中で調査され、日々新たな脆弱性が報告される
– アプリケーションの脆弱性を悪用される
• 個別のアプリケーションの脆弱性
• SQLインジェクションなど
5


# Page. 6

![Page Image](https://bcdn.docswell.com/page/PLJ1D5NXEG.jpg)

脆弱性とは何か
• 脆弱性とは、悪用可能なバグ、設定不備など
• 悪用可能なバグの例
– バッファオーバーフロー
– SQLインジェクション
– クロスサイト･スクリプティング
• 悪用可能な設定不備の例
–
–
–
–
デフォルトのパスワードのまま放置している
パスワードとして「password」を設定している
任意のメールを中継する設定（オープンリレー）
インターネット経由で誰でも使えるPROXY
6


# Page. 7

![Page Image](https://bcdn.docswell.com/page/8GJWY54K72.jpg)

【参考】CVEとCWE
• 脆弱性の国際的な分類として CVE と CWE がある
• CVE(Common Vulnerabilities and Exposures)
– 個別ソフトウェアの具体的な脆弱性を識別する番号
– 米国政府の支援を受けた非営利団体のMITRE社が採番
– CVEの例
• CVE-2017-1001000 WordPress Rest APIの脆弱性
• CVE-2017-5638 Apache Struts2の脆弱性S2-045
• CWE（Common Weakness Enumeration）
– 脆弱性の種類を識別する番号
– MITRE社が中心となって策定
– CWEの例
• CWE-89 SQLインジェクション
• CWE-22 ディレクトリトラバーサル
参考: https://www.ipa.go.jp/security/vuln/CVE.html
https://www.ipa.go.jp/security/vuln/CWE.html
7


# Page. 8

![Page Image](https://bcdn.docswell.com/page/W4EZXN2N73.jpg)

CWEの脆弱性タイプの階層構造図
https://www.ipa.go.jp/security/vuln/CWE.html より引用
8


# Page. 9

![Page Image](https://bcdn.docswell.com/page/KY7648V9JV.jpg)

CWE-20 不適切な入力確認
9


# Page. 10

![Page Image](https://bcdn.docswell.com/page/5G75Q9DDJ4.jpg)

Java セキュアコーディングスタンダード CERT/Oracle 版
•
•
•
•
•
•
•
•
•
•
はじめに
00. 入力値検査とデータの無害化 (IDS)
01. 宣言と初期化 (DCL)
02. 式 (EXP)
03. 数値型とその操作 (NUM)
04. オブジェクト指向 (OBJ)
05. メソッド (MET)
06. 例外時の動作 (ERR)
07. 可視性とアトミック性 (VNA)
08. ロック (LCK)
• 09. スレッド API (THI)
• 10. スレッドプール (TPS)
• 11. スレッドの安全性に関する雑則
(TSM)
• 12. 入出力 (FIO)
• 13. シリアライズ (SER)
• 14. プラットフォームのセキュリティ
(SEC)
• 15. 実行環境 (ENV)
• 49. 雑則 (MSC)
• AA. 参考情報
• BB. Glossary
https://www.jpcert.or.jp/java-rules/
10


# Page. 11

![Page Image](https://bcdn.docswell.com/page/V9J2P5MMJR.jpg)

IDS00-J. 信頼境界を越えて渡される信頼できないデータは無害化する
多くのプログラムは、認証済みでないユーザやネットワーク接続等、信頼できない情
報源からデータを受け取り、それを（改変したり、あるいはそのまま）信頼境界
（trust boundary）を越えて、信頼される側に渡す。多くの場合、データは、一定のシ
ンタックスを持つ文字列であり、プログラム内部のサブシステムによって解析される。
不正な形式の入力データには対応できないかもしれないし、インジェクション攻撃が
含まれているかもしれないため、そのような入力データは無害化（sanitize）しなくて
はならない。
特にコマンドインタプリタやパーサに渡される文字列データはすべて、解析される文
脈で無害な状態（innocuous）にしなければならない。
コマンドインタプリタやパーサの多くは、独自の無害化メカニズムや検査機構を備
えている。可能であれば、それらの無害化メカニズムを使用するほうが、独自に無害
化メカニズムを実装するよりも好ましい。独自に実装した無害化メカニズムでは、特
殊なケースやパーサの複雑な内部構造に配慮しない実装を行ってしまう可能性がある。
それだけでなく、コマンドインタプリタやパーサに新しい機能が追加されたとき、無
害化メカニズムが適切にメンテナンスされない恐れもある。
アーカイブ http://web.archive.org/web/20150515043831/ https://www.jpcert.or.jp/java-rules/ids00-j.html
11


# Page. 12

![Page Image](https://bcdn.docswell.com/page/5DEY5KXPEM.jpg)

どのような場所で検証？

エントリーポイント



ユーザによる入力
他システムとの連携ポイント
信頼境界

ここを超えるデータを検証
信頼境界
先程の現実世界の例と同様に、すべ
ての入り口、つまりエントリポイン
トでデータを検証（チェック）すべ
きです。
たとえば、SQLインジェクションは
悪意のある、なしにかかわらず、
ユーザが入力したデータを検証せず
に、そのままSQL文の一部として利
用してしまった場合に発生します。
【中略】
一方、すでに検証済みの信頼のおけ
るデータはそのまま利用することが
できます。先程の例では、高い塀の
内側にある場合がそれです。この壁
を信頼境界といいます。
http://download.microsoft.com/download/3/e/e/3ee9501d-df73-41e9-baba-a1b4e41cb1ba/SecurityL100dataissue_6.ppt
12


# Page. 13

![Page Image](https://bcdn.docswell.com/page/2VJNNR1MJ8.jpg)

こうですか、わかりません (&gt;_&lt;)/
信頼境界を越えて渡される信頼できないデータは無害化する
信頼境界
信頼できないデータ
無害化
フィルタ
無害なデータ
SQL
呼び出し
13


# Page. 14

![Page Image](https://bcdn.docswell.com/page/GYE9RM5W73.jpg)

こうですか、わかりません (&gt;_&lt;)/
信頼境界を越えて渡される信頼できないデータは無害化する
信頼境界
信頼できないデータ
無害化
フィルタ
無害なデータ
SQL
呼び出し
14


# Page. 15

![Page Image](https://bcdn.docswell.com/page/5GE8WLYR7D.jpg)

IDS00-J. 信頼境界を越えて渡される信頼できないデータは無害化する
多くのプログラムは、認証済みでないユーザやネットワーク接続等、信頼できない情
報源からデータを受け取り、それを（改変したり、あるいはそのまま）信頼境界
（trust boundary）を越えて、信頼される側に渡す。多くの場合、データは、一定のシ
ンタックスを持つ文字列であり、プログラム内部のサブシステムによって解析される。
不正な形式の入力データには対応できないかもしれないし、インジェクション攻撃が
含まれているかもしれないため、そのような入力データは無害化（sanitize）しなくて
はならない。
特にコマンドインタプリタやパーサに渡される文字列データはすべて、解析される文
脈で無害な状態（innocuous）にしなければならない。
コマンドインタプリタやパーサの多くは、独自の無害化メカニズムや検査機構を備
えている。可能であれば、それらの無害化メカニズムを使用するほうが、独自に無害
化メカニズムを実装するよりも好ましい。独自に実装した無害化メカニズムでは、特
殊なケースやパーサの複雑な内部構造に配慮しない実装を行ってしまう可能性がある。
それだけでなく、コマンドインタプリタやパーサに新しい機能が追加されたとき、無
害化メカニズムが適切にメンテナンスされない恐れもある。
アーカイブ http://web.archive.org/web/20150515043831/ https://www.jpcert.or.jp/java-rules/ids00-j.html
15


# Page. 16

![Page Image](https://bcdn.docswell.com/page/MLELNL42JR.jpg)

IDS00-J. 信頼境界を越えて渡される信頼できないデータは無害化する
違反コード
以下の違反コード例は、ユーザ認証を行うJDBCのコードを示している。パスワードは
char型配列として渡され、データベースへの接続が作成され、パスワードがハッシュ
化されている。
残念ながらこのコードはSQLインジェクション攻撃を許してしまう。SQL文 sqlString
は無害化されていない入力値を受け付けており、前述の攻撃シナリオが成立してしま
うだろう。
適合コード (PreparedStatement)
幸いJDBCライブラリはSQLコマンドを組み立てるAPIを提供しており、信頼できない
データを無害化してくれる。java.sql.PreparedStatementクラスは入力文字列を適切に
エスケープ処理するため、適切に利用すればSQLインジェクション攻撃を防ぐことが
できる。これはコンポーネントベースで行う無害化の一例である。
この適合コードでは java.sql.Statement の代わりに PreparedStatementを使用するよう
に doPrivilegedAction() メソッドを変更している。また、引数 username の長さを検
証しており、攻撃者が任意に長いユーザ名を送り込むことを防止している。
アーカイブ http://web.archive.org/web/20150515043831/ https://www.jpcert.or.jp/java-rules/ids00-j.html
16


# Page. 17

![Page Image](https://bcdn.docswell.com/page/54JMXMK97W.jpg)

こうだった
信頼境界を越えて渡される信頼できないデータは無害化する
信頼境界
プレースホルダ
信頼できないデータ
安全な形でSQL
呼び出し
17


# Page. 18

![Page Image](https://bcdn.docswell.com/page/ZPJRNVX979.jpg)

そもそも信頼境界関係なくね?
18


# Page. 19

![Page Image](https://bcdn.docswell.com/page/NPEXNZ63JX.jpg)

そう、故に見出しが改定された
19


# Page. 20

![Page Image](https://bcdn.docswell.com/page/63EKN81NED.jpg)

まさかの「SQLインジェクションを防ぐ」
信頼境界も、信頼できないも、無害化も
タイトルから消えた
https://www.jpcert.or.jp/java-rules/ids00-j.html
20


# Page. 21

![Page Image](https://bcdn.docswell.com/page/4L73V2QZE5.jpg)

では、信頼境界は無意味?
21


# Page. 22

![Page Image](https://bcdn.docswell.com/page/V87D8Z947G.jpg)

そうでもない
22


# Page. 23

![Page Image](https://bcdn.docswell.com/page/4VJP8DZVJ8.jpg)

こういうのはダメ
hiddenパラメータでSQL文を渡している
信頼境界
hiddenパラメータで
SQL文を渡している
SQL呼び出し
23


# Page. 24

![Page Image](https://bcdn.docswell.com/page/L2EVN1WR7Q.jpg)

phpMyAdminの場合
DB管理者
信頼境界
認証・認可
SQL呼び出し
SQL文
信頼できる情報源
SQL文
SQL文
ソースコード
セッション変数
データベース
設定ファイル
…
24


# Page. 25

![Page Image](https://bcdn.docswell.com/page/Z57GK2D6JL.jpg)

「安全なウェブサイトの作り方」に出てくる信頼境界の例
• SQLインジェクション
– ウェブアプリケーションに渡されるパラメータにSQL文を直接指定しない。
• OSコマンドインジェクション
– Perlのopen関数は、引数として与えるファイルパスに「|」（パイプ）を使うことでOS
コマンドを実行できるため、外部からの入力値を引数として利用する実装は危険です
• ディレクトリトラバーサル
– 外部からのパラメータでウェブサーバ内のファイル名を直接指定する実装を避ける
– ファイルを開く際は、固定のディレクトリを指定し、かつファイル名にディレクトリ
名が含まれないようにする。
• XSS
– 入力されたHTMLテキストから構文解析木を作成し、スクリプトを含まない必要な要
素のみを抽出する
– 入力されたHTMLテキストから、スクリプトに該当する文字列を排除する
25


# Page. 26

![Page Image](https://bcdn.docswell.com/page/V4EQNP12EP.jpg)

「信頼されたデータ」が要求される例
• 信頼境界の中のデータ
–
–
–
–
–
–
プログラムコード
SQL文
evalの入力
設定ファイル名に記載されたファイル名
正規表現
オブジェクト
• アプリケーションで「信頼できることを確認」
–
–
–
–
–
ログイン済みユーザ名（認証）
管理者が入力するSQL文（認可）
CMSに入力するHTML（認可）
制限されたHTML（フィルタリング）
外部からのファイル名（basename）
26


# Page. 27

![Page Image](https://bcdn.docswell.com/page/DKJ4GYRPE1.jpg)

信頼に関して…
• 安全に使う方法があれば「信頼」を気にしない
– SQL文のプレースホルダにバインドする値
– シェルを経由しないコマンド呼び出しのパラメータ
– 安全なメール送信APIに渡すメールアドレス
• 信頼するしかないデータもある
– プログラムコード、SQL文そのもの
– evalの入力、正規表現
– オブジェクト
• 認証やフィルタリングにより「信頼」できる場合
– basename関数を通したファイル名
– 認証されたユーザ名
– 権限を認可されたSQL文、HTMLテキスト
27


# Page. 28

![Page Image](https://bcdn.docswell.com/page/PLE1D6QX7G.jpg)

SQLインジェクション攻撃
28


# Page. 29

![Page Image](https://bcdn.docswell.com/page/8GEWYWMKJ2.jpg)

今日はこの本を題材として
使います
29


# Page. 30

![Page Image](https://bcdn.docswell.com/page/W47ZX5QNJ3.jpg)

日本で一番売れているPHP教科書のサンプル
// ここまでで、認証済みであるこの検査が済んでいる
$id = $_REQUEST[&#039;id&#039;];
// 投稿を検査する
$sql = sprintf(&#039;SELECT * FROM posts WHERE id=%d&#039;,
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(&#039;DELETE FROM posts WHERE id=&#039; .
mysql_real_escape_string($id)) or die(mysql_error());
}
ここにSQLインジェクション
しかし、DELETE FROM
文なので表示はない
たにぐちまこと、「よく分かるPHPの教科書」 P272より引用
30


# Page. 31

![Page Image](https://bcdn.docswell.com/page/KYJ64969EV.jpg)

エスケープしているのになぜSQLインジェクション?
$id = ’88-1’; で説明。これはエスケープ後も 88-1
$sql = sprintf(&#039;SELECT * FROM posts WHERE id=%d&#039;, 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が削除される
31


# Page. 32

![Page Image](https://bcdn.docswell.com/page/5GJ5QN6DE4.jpg)

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)&gt;=&#039;M&#039;, &#039;a&#039;,
&#039;ab&#039;)))
• WHERE句の中 18-(SELECT … WHERE …)
• 中のWHERE句は
LIKE 述語にESCAPE句がある
• ESCAPE句はIF関数により、membersの1行目の1文字目が
’M’以上の場合’a’、それ以外の場合’ab’
• SQL文の文法上、ESCAPE句は1文字以外だとエラー
• この結果を繰り返すことによって、対象文字列を絞り込む
→ブラインドSQLインジェクション
32


# Page. 33

![Page Image](https://bcdn.docswell.com/page/V9E2P5NMER.jpg)

SQLインジェクションはなぜ危険か?
• 攻撃対象サーバーのデータベースについて、攻撃者が自由にSQL呼び
出しができる
• データベースの中身の漏洩、改ざんが起こる
• 脆弱性のあるテーブルだけでなく、データベース内のすべてのデータ
が漏洩できる。場合によっては改ざんも
• 使い勝手の良い攻撃ツール（SQL注入工具:名目は診断ツール）が安価
で流通している
• SQL注入工具はExcel使うより簡単だよ
33


# Page. 34

![Page Image](https://bcdn.docswell.com/page/5D7Y5KPP7M.jpg)

SQLインジェクション対策はプレースホルダで
• プレースホルダとは
SELECT * FROM books WHERE id=?
• 静的プレースホルダと動的プレースホルダ
– 静的: サーバー側で値をバインドする（エスケープは必要ない）
– 動的: 呼び出し側で値をエスケープしてバインドする
• 接続時に文字エンコーディングを指定する
$db = new PDO(&#039;mysql:host=myhost;dbname=mydb;charset=utf8&#039;,
DBUSER, DBPASS);
• 列の型を意識する
34


# Page. 35

![Page Image](https://bcdn.docswell.com/page/2VENNR5ME8.jpg)

サンプルコード（PHP5.5.21以降）
// エミュレーションモードOFF = 静的プレースホルダ
$opt = array(PDO::ATTR_EMULATE_PREPARES =&gt; false,
// 「複文」を禁止する （PHP 5.5.21 / PHP 5.65 以降で有効）
PDO::MYSQL_ATTR_MULTI_STATEMENTS =&gt; false);
// 文字エンコーディング指定は PHP 5.3.7 以降
$db = new PDO(&#039;mysql:host=myhost;dbname=mydb;charset=utf8&#039;, DBUSER, DBPASS, $opt);
// プレースホルダを使ってSQLを準備
$prepare = $db-&gt;prepare(&#039;SELECT * FROM example WHERE id = :id and language = :lang&#039;);
// 型を指定してbind （キャストはPDOのバグ対策）
$prepare-&gt;bindValue(&#039;:id&#039;, (int) $int, PDO::PARAM_INT);
$prepare-&gt;bindValue(&#039;:lang&#039;, $str, PDO::PARAM_STR);
$prepare-&gt;execute();
※ 実際には try { … } catch … による例外処理を追加すること
35


# Page. 36

![Page Image](https://bcdn.docswell.com/page/GY79RMYWJ3.jpg)

成りすまし犯行予告…ただし、マルウェアではなく、CSRF脆弱
性でやってみる
横浜市の事
例パターン
36


# Page. 37

![Page Image](https://bcdn.docswell.com/page/5G78WL6RJD.jpg)

横浜市のCSRF悪用の犯行予告手口（推測）
http://d.hatena.ne.jp/Kango/20121008/1349660951 より許諾を得て引用
37


# Page. 38

![Page Image](https://bcdn.docswell.com/page/ML7LNL92ER.jpg)

日本で一番売れているPHP教科書のサンプル
005: if (isset($_SESSION[&#039;id&#039;]) &amp;&amp; $_SESSION[&#039;time&#039;] + 3600 &gt; time()) {
006:
// ログインしている 省略
014: } else {
015:
// ログインしていない
016:
header(&#039;Location: login.php&#039;); exit();
017: }
018:
CSRF脆弱性
019: // 投稿を記録する
対策していない
020: if (!empty($_POST)) {
021:
if ($_POST[&#039;message&#039;] != &#039;&#039;) {
022:
$sql = sprintf(&#039;INSERT INTO posts SET member_id=%d, message=&quot;%s&quot;,
reply_post_id=%d, created=NOW()&#039;,
023:
mysql_real_escape_string($member[&#039;id&#039;]),
024:
mysql_real_escape_string($_POST[&#039;message&#039;]),
025:
mysql_real_escape_string($_POST[&#039;reply_post_id&#039;])
026:
);
027:
mysql_query($sql) or die(mysql_error());
028:
続きはデモで
029:
header(&#039;Location: index.php&#039;); exit();
030:
}
031: }
たにぐちまこと著「よくわかるPHPの教科書」より引用
38


# Page. 39

![Page Image](https://bcdn.docswell.com/page/54EMXMZ9JW.jpg)

CSRFによる成りすまし投稿
③被害者のブラウザ経由
で掲示板に書き込み
掲示板の書き込みログは
被害者のIPアドレス
39


# Page. 40

![Page Image](https://bcdn.docswell.com/page/ZPERNV69J9.jpg)

CSRF対策の方法は?
•
•
•
•
色々な対策が知られている
トークンによるもの
再認証
Refererのチェック
• Captcha
• …
• 実際は、トークン一択と考えて良い
40


# Page. 41

![Page Image](https://bcdn.docswell.com/page/NP7XNZM3EX.jpg)

トークンはどうやって生成する?
• ワンタイムトークンである必要はない
– セッション毎に固定で良い
– いわゆるワンタイムトークンだと処理が複雑になる
• セッション毎に一度「安全な乱数生成器」で生成する
– 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とセッションの両方に書いておいて、両者を比較
する。違っていたらエラー
41


# Page. 42

![Page Image](https://bcdn.docswell.com/page/637KN8GN7D.jpg)

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


# Page. 43

![Page Image](https://bcdn.docswell.com/page/4LJ3V2NZ75.jpg)

XSSはなぜ危険か?
• XSSは、
– 利用者（被害者）のブラウザ上で
– 攻撃対象のドメイン（オリジン）で
– 攻撃者が自由にJavaScriptを実行できる
• これって、ウイルス?
– ウイルスではないが、結果としてウイルスと同じような被害
– XSSを悪用したウイルス（ワーム）はいくつかある
• ブラウザを乗っ取られたのと同じ
– 影響範囲はXSS脆弱性のあるページと同じドメイン（オリジン）
– 同一オリジン上はすべてのページが影響を受ける
※オリジン=ホスト名+スキーム+ポート番号
43


# Page. 44

![Page Image](https://bcdn.docswell.com/page/V8JD8ZW4JG.jpg)

XSSのデモ
• 先ほどのCSRF対策済みの掲示板で、なりすまし書き込みをやってみる
• 実行するスクリプトは下記のもの
※ オリジナルの書籍にはこの脆弱性はありません
メモ
&lt;script&gt;
var s = document.body.innerHTML;
if (s.indexOf(&#039;徳丸浩さん、&#039; + &#039;メッセージをどうぞ&#039;) &gt;= 0 &amp;&amp;
s.indexOf(&#039;〇〇小学校を襲&#039; + &#039;撃します&#039;) &lt; 0) {
var token = document.getElementsByName(&#039;token&#039;)[0].value;
var req = new XMLHttpRequest();
req.open(&#039;POST&#039;, &#039;index.php&#039;);
req.setRequestHeader(&#039;Content-Type&#039;, &#039;application/x-www-form-urlencoded&#039;);
data = &#039;message=〇〇小学校を襲&#039; + &#039;撃します&amp;token=&#039;+token;
req.send(data);
}
&lt;/script&gt;
44


# Page. 45

![Page Image](https://bcdn.docswell.com/page/4VEP8D9VE8.jpg)

XSSの対策
• 文脈に応じてHTMLエスケープ
– エスケープするタイミングは表示の直前
– PHPの場合、htmlspecialcharsの引数に注意
• 第2引数は、文脈により変えるか、ENT_QUOTES固定
• 第3引数はPHP内部の文字エンコーディングを指定
PHP5.3までのデフォルトは ISO-8859-1
PHP5.4, 5.5のデフォルトは UTF-8
PHP5.6からはデフォルトとして default_charset
• 属性値はダブルクオートで囲む
• レスポンスヘッダで文字エンコーディングを指定
– Content-Type: text/html; charset=UTF-8
• JavaScriptの動的生成を避ける
– HTML上に値を書いてJavaScriptから参照
45


# Page. 46

![Page Image](https://bcdn.docswell.com/page/L27VN1MRJQ.jpg)

ファイルアップロードに関連して
46


# Page. 47

![Page Image](https://bcdn.docswell.com/page/Z5JGK2G6EL.jpg)

日本で一番売れているPHP教科書のサンプル（ユーザ登録）
join/index.php
20: $fileName = $_FILES[&#039;image&#039;][&#039;name&#039;];
21: if (!empty($fileName)) {
22:
$ext = substr($fileName, -3);
23:
if ($ext != &#039;jpg&#039; &amp;&amp; $ext != &#039;gif&#039;) {
24:
$error[&#039;image&#039;] = &#039;type&#039;;
25:
}
26: }
ファイル名の末尾3文字（拡張子）のみ確認
アップロードファイルをドキュメントルート下に保存
40: if (empty($error)) {
41:
// 画像をアップロードする
42:
$image = date(&#039;YmdHis&#039;) . $_FILES[&#039;image&#039;][&#039;name&#039;];
43:
move_uploaded_file($_FILES[‘image’][‘tmp_name’], ‘../member_picture/’ . $image);
44:
$_SESSION[&#039;join&#039;] = $_POST;
46:
$_SESSION[&#039;join&#039;][&#039;image&#039;] = $image;
ファイル名をHTMLエスケープしないで表示
join/check.php
58: &lt;img src=&quot;../member_picture/&lt;?php echo $_SESSION[&#039;join&#039;][&#039;image&#039;]; ?&gt;&quot; … /&gt;
たにぐちまこと著「よくわかるPHPの教科書」より引用
47


# Page. 48

![Page Image](https://bcdn.docswell.com/page/V47QNPX27P.jpg)

「よくわかるPHPの教科書」のアップロードにはいくつかの問題がある
• 画像ファイル名をエスケープしないで表示している…潜在的なXSS
• アップロード画像をドキュメントルート下に保存
– PHP等のファイルをアップロードされる可能性
– 拡張子（末尾3文字）のチェックはしているが…
• ドットのチェックをしていないので foogif みたいなファイル名も許容
– 抜けはないのか?
• アップロード後のファイル名が、日付日時 + 元ファイル名 という採
番ルール
– 同時刻に同名のファイルをアップロードされたらファイル名が衝突する
48


# Page. 49

![Page Image](https://bcdn.docswell.com/page/DKE4GY6P71.jpg)

本当に「潜在的な」XSSなのか?
• ファイルアップロードフォームで、ファイル名を外部から指定する方
法はあるか?
&lt;input type=&quot;file&quot; name=&quot;image&quot; size=&quot;35&quot; value=&quot;test&quot; /&gt;
49


# Page. 50

![Page Image](https://bcdn.docswell.com/page/PL71D6VXJG.jpg)

IE / Edge なら攻撃できる
以下のHTTPリクエストを送信させる必要があるが…
------WebKitFormBoundaryj4Hx293np6E9kb7T
Content-Disposition: form-data; name=“foo”; filename=&quot;攻撃文字列&quot;
1
------WebKitFormBoundaryj4Hx293np6E9kb7T--
Content-Disposition: form-data; name=&quot;foo“; filename=&quot;攻撃文字列&quot;
&lt;select name=‘foo“; filename=”攻撃文字列’&gt; ← 左のようにすると…
------WebKitFormBoundaryj4Hx293np6E9kb7T
Content-Disposition: form-data; name=&quot;foo&quot; filename=&quot;攻撃文字列&quot;
※ この攻撃方法は三井物産セキュアディレクションの望月岳氏にご教授いただきました
50


# Page. 51

![Page Image](https://bcdn.docswell.com/page/8G7WYWLKE2.jpg)

XSS発火用スクリプト
&lt;form enctype=“multipart/form-data&quot;
action=&quot;http://park.jp/minibbs/join/index.php&quot; method=&quot;POST&quot;&gt;
&lt;input name=&quot;name&quot; value=&quot;taro&quot;&gt;&lt;br&gt;
&lt;input name=&quot;email&quot; value=&quot;a@example.jp&quot;&gt;&lt;br&gt;
&lt;input name=&quot;password&quot; value=&quot;123456&quot;&gt;&lt;br&gt;
&lt;select name=&#039;image&quot;;
filename=&quot;¥&quot;&gt;&lt;img src=a onerror=alert(document.cookie)&gt;.gif&#039;&gt;
&lt;option value=&quot;&lt;?php phpinfo(); ?&gt;&quot; selected&gt;1&lt;/option&gt;
&lt;/select&gt;
&lt;input type=&quot;submit&quot; value=&quot;submit&quot; /&gt;
&lt;/form&gt;
51


# Page. 52

![Page Image](https://bcdn.docswell.com/page/W4JZX5MNE3.jpg)

PHPスクリプトをアップロードされる心配は?
• PHP等のスクリプトをアップロードされる危険がある
• 拡張子（末尾3文字）が jpg または gif に限定されているので、拡張
子 .php のファイルは弾かれる…はずだが
• Apacheの設定で foo.php.gif 等の二重拡張子が有効な場合
• PHPスクリプトを実行される余地がある
52


# Page. 53

![Page Image](https://bcdn.docswell.com/page/KYE649N97V.jpg)

む、難しい…
• PHP入門書として、あまり難しいことも書けないのではないか?
• 実は、多くの脆弱性は、局所的に対策をとっておけば避けられる
• 以下のような中途半端な「判断」が危ない
– ファイル名文字列だからXSSはできない
• 局所的な対策を積み重ねること
• 同じ処理は同じように書きましょぅ
– チェックと更新で条件が違うのは脆弱性の元
– WordPress REST APIのCVE-2017-1001000 もこれが原因
53


# Page. 54

![Page Image](https://bcdn.docswell.com/page/5GE5QN5D74.jpg)

まとめ
•
•
•
•
•
•
侵入を受けるウェブサイトとはどういう状況なのか？
入力値の問題
SQLインジェクション
クロスサイト・リクエストフォージェリ(CSRF)
クロスサイト・スクリプティング(XSS)
アップロードの問題
54


