▼2017年4月11日火曜日teratailに投稿されたメールフォームにCSRF脆弱性が残存した理由teratailに以下のような投稿がありました。PHPでメールフォームを作成したので、脆弱性がないかアドバイスいただけないでしょうか。作り方」でググって表示されるサイトを見ると、「んんんんん???」と思うところがあります。これらを参考にしたり、コピペする方は、記述されているコードの良し悪しは判断できないかと思います。そのような方々が参考にできるメールフォームを作りたいという思いで、調べて作りました。)ペコ【PHP】作成したメールフォームに脆弱性がないか、アドバイスもらえないでしょうかより引用どれどれ...と確認すると、トークンのチェックが入っているにも関わらずクロスサイト・リクエストフォージェリ(CSRF)脆弱性が残存しています。Concept)を回答し、CSRF脆弱性があることを指摘しましたが、質問者の学習機会を奪わないためにわざと解説は省きました。本稿では、この脆弱性のメカニズムについて報告します。処理概要このメールフォームは、元記事に以下のように書かれているように、典型的な入力・確認・送信の3ステップからなります。画面を遷移してメールを送ります。以下、各ステップの処理概要を示します。続いて、CSRF攻撃について検討します。外部からPOSTされるまずは、いきなり送信ページ(send.php)に対してPOSTする場合を考えましょう。この場合、セッション変数は初期化されていないわけですから、$_SESSION['token]はNULLという扱いになりますが、前述のように、この場合$_SESSION['token']は空文字列が入ります。したがって、POSTするトークンとして空文字列を送ってやれば、CSRF対策を回避できます。問い合わせしたユーザのメールアドレスや問い合わせ内容はセッション変数経由で受け渡しをしているため、いずれもNULLとなります。このためメールも送信されない...わけではなく、管理者向けに内容が空(テンプレートのみ)のメールが送信されます。すごい実害があるわけではありませんが、嫌がらせ程度には使えるかもしれません。空文字列のトークンでCSRF対策が回避できることは、大きな問題です。続けてPOSTされる次の攻撃パターンは、まずconfirm.phpに外部からPOSTし、少し時間をおいてsend.phpにPOSTする攻撃です。$_SESSION['token']は空文字列が入ります。したがって、POSTするトークンとして空文字列を送ってやれば、CSRF対策を回避できます。加えて、問い合わせ内容を攻撃の趣旨に合わせてPOSTすれば、バリデーションを経てセッション変数にセットされます。後は、脅威1と同じようにsend.phpをPOSTすることで、上記でセットした問い合わせ内容が、被害者のブラウザから送信されることになります。私のPoCでは、被害者のブラウザから「犯行予告」を問い合わせとして送るようにしましたが、他の悪用もあり得るでしょう。NULLのトークンを空文字列にしなければ問題ないのか?confirm.phpとsend.phpではセッション変数のトークンがNULLの場合、空文字列に置き換えています。典型的な「余計なお世話」ですが、これがなければ脆弱とはならないでしょうか。CSRF対策をすり抜けます。具体的には、POSTパラメータtokenを送らないことにより実現可能です。トークンのNULLチェックをしていて、トークンがNULLということは正常な遷移ではないわけですから、この時点でエラーとして処理を終了すればCSRF脆弱性は防げました。バリデーションでセッション変数のトークンが空でないことを確認すれば脆弱性は防げますが、お勧めしたいのは、以下のステップでもトークンが空でないことを確認することです。POSTされたトークンが$_SESSION['token']に一致しなければエラー表示すなわち、上記のルールを以下のように拡張します。POSTされたトークンが空であるか、または$_SESSION['token']に一致しなければエラー表示トークンが空かどうかのチェックにはPHPのempty()を使うと良いでしょう。empty()は、NULLでも空文字列でもTRUEを返すので、これら両方をエラーにすることができます。なく、hash_equalsを使うとよいでしょう。返すので、トークンがNULLなのにトークンチェックをすり抜けることが防げます。まとめると以下のようになります。hash_equalsによりトークンを比較するバリデーションでトークンが空でないことを確認すればいいではないかと思う人もいると思いますが、脆弱性の対策は局所的に行うことが重要なのです。することで、脆弱性がないことが一目で確認でき、脆弱性が入りにくくなり、後から「脆弱性がないことを確認する」際にも時間を節約することができます。まとめteratailに投稿された問い合わせフォームを題材として、CSRF対策の漏れやすいポイントを紹介しました。脆弱性診断の実務でも、トークンを空文字列にするとか、トークン自体を削除することでCSRF対策がすり抜けてしまうことはままあります。局所的にトークンが空でないことを確認することにより、このような対策漏れを防ぐことが可能です。