はじめに
この記事は弊研究室の某課題について考える19日目の記事です
今日はCSRFの話、正直言葉は知ってる人多いと思うけど内容知らない人が多そうだと思ったので記事にします。CSRF自体の解説は他のサイトでもいっぱいされているのでそっちを見てもよし!
CSRFとは
CSRFとはクロスサイトリクエストフォージェリ(cross-site request forgeries)の略称でありWebアプリケーションの脆弱性の一つ、もしくはそれを利用した攻撃を指します。
具体的な被害としては以下のものが挙げられます
- データ漏洩
- 意図しないコードの実行
- 権限の取得
- なりすまし
- アプリケーションデータの読み取り
こんな感じでしっかりと対策を行うべき脆弱性です。
CSRFは以下の状況で発生します
- クッキーのみでセッション管理が行われているサイト
- HTTP認証、SSLクライアント証明書、携帯電話の携帯IDのみで利用者の識別が行われているサイト
CSRFの例
docker-composeで手元でも確認できる環境を用意しました!やったね!!手元確認しない人用に重要な部分のソースコードは載せます。
先に書きます。徳丸本を参考にしてます
パスワード変更のサンプル(passwd.php)
<?php
function h($str){
return htmlspecialchars($str, ENT_NOQUOTES, 'UTF-8');
}
session_start();
// ログイン確認---省略
$id = $_SESSION['id'];
?>
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="Content-Security-Policy" contents="default-src 'self'; script-src 'self';">
<title>Login form</title>
<link rel="stylesheet" type="text/css" href="report.css">
</head>
<body>
<div class="top19">
<div class="box19">
<h1>Password Change</h1>
<form action="passchange.php" method="POST">
新パスワード : <input name="pwd" type="password"><br>
<input type="submit" value="パスワード変更">
</form>
</div> <!-- box19 -->
</div>
</body>
</html>
POST送信の先(passchange.php)
<?php
function h($str){
return htmlspecialchars($str, ENT_NOQUOTES, 'UTF-8');
}
session_start();
$id = $_SESSION['id'];
// ログイン確認---省略
$pwd = $_POST['pwd'];
// パスワード変更処理
?>
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="Content-Security-Policy" contents="default-src 'self'; script-src 'self';">
<title>Login form</title>
<link rel="stylesheet" type="text/css" href="report.css">
</head>
<body>
<div class="top19">
<div class="box19">
<h1>Password Change</h1>
<?php echo h($id); ?>さんのパスワードを<?php echo h($pwd); ?>に変更しました!
</div> <!-- box19 -->
</div>
</body>
</html>
この一連のページはパスワードの変更を行うものである。パスワード変更の流れは
となっているが、2つめのログインを確認する場面を正しく行わないとCSRFが発生する。
対策方法は後で述べるとして攻撃方法を示す。
上のページにアクセスした後にcrack.htmlにアクセスするとpasswordがcrackedに変更されたメッセージが確認できると思います
<body onload="document.forms[0].submit()" > <form action="http://[hostname]:4455/passchange.php" method="POST"> <input type="hidden" name="pwd" value="cracked"> </form> </body>
上記例においてCSRFが発生する状況
ログイン確認の部分を記述していませんがここをしっかりすれば上の状況でもCSRFは発生しません。
ログイン確認の部分に固定の値ではなく乱数を含めたセッションidを用いればよいのです(セッションidは一定時間で変更するとなおよし)
<input type="hidden" name="sessionid" value="セッションidのもの">
送信されてきたセッションidと通信しているセッションidが同じであれば本人の通信であるという保証が得られます。
CSRFの対策
基本的には利用者の操作とアクセスが一致しているかどうかを確認することに尽きると思います。
もっと知りたい方は徳丸本を買いましょう。そして徳丸本は6月に改訂されるらしいです