RequestPolicyを試してみる
「NoScript」をやめて「RequestPolicy」にした で紹介されていたので、RequestPolicy (0.5.5) を使ってみた。
このプラグインは、訪問先のドメイン*1ごとに、別ドメインへの(ユーザが明示的に行った場合以外の)リクエストの許可/不許可を設定できる、というもの。RequestPolicy は無許可での他ドメインのコンテンツのロードを禁止してくれるので、JavaScriptがオフでも防げないclickjacking のような攻撃も防御できるし、NoScriptの「信頼して何でも許可していたサイトがクラックされたら、やりたい放題」という点をカバーできる。公式サイトのFAQにあるとおり、NoScriptの対抗馬というわけではなく、別のアプローチからセキュリティとプライバシーを守りましょう、という感じらしい。あと、リクエストのログが確認できるので、どんなリクエストがブロックされたかを確認でき、要不要の判断もしやすい。なかなかいい感じ。
一応以下のようなページで、いくつかのパターン
- onload
- ユーザの操作がトリガーにはなるけど、無関係のformを送信
- ユーザの操作がトリガーで、さらに同一のformを送信
<html> <body onload="document.forms[0].submit();"> <a href="#" onclick="document.forms[0].submit();">ただのリンクですよ</a> <form action="http://example.com/"> <input type="text" onkeypress="this.form.submit();" /> <input type="submit" /> </form> </body> </html>
も試したけど、きちんとブロックしてくれた。submitボタンを押したときだけは確認なしに送信が行われるけど、これは明示的なリクエストの結果だから問題ないと思う*2。
ただ、よくわからない挙動もある。たとえば上のページを訪問した際、最初はきちんとブロックしてくれるんだけど、一回 submit ボタンを押して能動的にform送信を行うと、もう一度上記のページを訪問したときには、何も許可設定を追加していないのに今度は勝手にフォーム送信が行われてしまった。
ユーザが明示的にsubmitを行うと、「安全な送信先」だということを一時的に記憶してくれたりしているんだろうか。個人的には、余計な機能だと思うんだけど……。まあ、Firefoxを再起動するともう一度ブロックしてくれるみたいだし、別ページの同一送信先へのフォームや、同じフォームの送信先を書き換えたりした場合もブロックしてくれるので、問題にはならないのかな。
追記
ちょこっと見てみたら、「能動的なリクエストか自動リクエストか」を判断するのは、やっぱりRequestPolicyががんばっているみたい。たとえばこんなことが書いてあった(以下、chrome/requestpolicy.jar/content/overlay.js から引用)。
// Add a submit handler so we can register all form submissions and be // able to allow them. // As far as I can tell, calling a form's submit() method from // javascript will not cause this event listener to fire even though it // will submit the form, which makes things easier in that we don't have // to find another way to tell if the user submitted the form or if it // was done by javascript. However, I'm not sure on the specifics of why // submit() from javascript doesn't end up calling this. I can only // conclude it's the ame difference as with link clicks by humans vs. // click(), but that the documentation just doesn't state this (with the // exception that nonprivileged code can call submit(), but it just // doesn't result in a submit event going through the DOM). appcontent.addEventListener("submit", function(event) { if (event.target.nodeName.toLowerCase() != "form") { return; } requestpolicyOverlay._rpService.registerFormSubmitted( event.target.ownerDocument.URL, event.target.action); }, true);
上で書いた「よくわからない挙動」の仕組みとしては、
- 上のように、イベントを監視して、正当なリクエストと判断したらその送信元と送信先を RequestPolicy 内部に登録する。例えば RequestPolicyService の registerFormSubmitted は RequestPolicy が内部で持っている「ちゃんと送信されたフォーム一覧」に送信元と送信先を登録するもの。
- その後、実際にリクエストを送ろうとするところを全てキャッチして、送信内容が「ちゃんと送信されたフォーム一覧」に含まれているならOKとする。
という感じの流れがあった上で、「ちゃんと送信されたフォーム一覧」はブラウザ再起動までクリアされないから、というのが理由っぽい。「ちゃんと送信されたフォーム一覧」に登録された「送信元」と「送信先」にはドメインだけでなくパス情報も含まれるから、別ページに置かれたフォームだったりするときちんとブロックされる。
なるほどねー。