さあ、どうすればよかったんでしょう。
きっかけはこちら
試しにやってみた話はこちら
ここ数回はCSRFについて書いて来ましたが、今回は対策について。なお、上のリンクはコメントも合わせて読んでおくとよいと思います。
必要なリクエスト以外を許可しない
最初に件の掲示板を公開したときは、GETメソッドでリクエストでも投稿ができるようになっていました。これは本来の「GET(得る)」の意味を考えてもよくない使い方ですね。なので、必要なメソッド*1でのリクエストでのみ投稿できるようにしておけば、この問題は解決できます。
ちなみに今はこの問題を解消していますので、GETメソッドで掲示板に投稿しようとしてもできないはずです。
リクエスト先を確認する
では今はどう攻撃しているかというと、GETメソッドでリクエストで攻撃を始めるのは相変わらずなのですが、それを受けて攻撃用のサイトを置いているサーバーから掲示板のサーバーにPOSTメソッドでリクエストを送って投稿しています。必要なリクエスト以外を許可しないだけだと不十分なんですね。ではどうすればよかったんでしょうか。
こちらはまだ対処をしていないのですが、リクエストヘッダーのRefererを確認し、所定のところ以外であれば投稿できないようにすればよさそうですね。Refererを送信していなかったり、他のサーバーから送ってきたりしていたらリクエスをと弾く、という風にしましょうか。
これだとまだ不十分
でも、これだとまだ突破されるんですよね。リクエストヘッダーは偽装できますから。
たとえば、PCのブラウザからスマートフォン向けのサイトを確認するためや、某掲示板のリクエスト規制を緩和するために、User-Agentをデフォルトのものから特定のものに書き換えるブラウザプラグインがあります。これと同じようにRefererを書き換えてやれば、あたかも正しいページから投稿されたように装うことができます。
これの対策がここで出てきた、自動生成されるhiddenパラメータによって渡されるトークンです。これは、
投稿ページ⇢投稿完了ページ(簡単のため投稿ページにリダイレクトされています)
という流れに沿ってちゃんと順を追って操作されていることを保証するためのものだったんですね。
このトークンが正しくないときや送られていないときは不正なリクエスト、ということで弾いてしまえばよいわけです。
その他にも
たとえば、プロフィールの変更や商品の購入などはもう一度IDやパスワードを求められることがありますよね。このように、アカウントがあるサービスなら、重要な部分で直前に再度認証を求めてCSRFへの対策ができます。
*1:今回はPUTメソッドを送っています