はじめに
はじめまして。株式会社iimonでフロントエンドエンジニアをしている川口と申します。私はiimonに入社して3か月目になりますが、業務内にCSRF-TOKENを扱う機会が何度かありました。CSRF-TOKENが何なのか何となくは分かっていながらも、概要しか理解していなかったため、この機会に理解を深めようと思い、記事にまとめました。
CSRFとは
CSRFとはCrossSiteRquestForgeryの略です。
名前の通り、サイトを跨いでリクエストを偽造するハッキングの手法のことなのですが、この説明だけではピンと来ない方もいると思うので例を紹介します。
CSRFの手法
隠されたinputタグに値を設定し、javascriptで送信する
<html> <form action="https://abc.bank.com/online/transfer" method="POST"> <input type="hidden" name="amount" value="500"> <input type="hidden" name="accountNumber" value="123456"> </form> <script> document.forms[0].submit(); </script> </html>
こちらのFormでは、あらかじめ送金先と送金額を仕込んであり、サイトを訪問するとjavascriptが発火し、Cookieに保存されているセッション情報と一緒にリクエストが送信されます。
実際にやってみる
今回は、実際にDjangoで作成した簡易的なToDoリストアプリに対してCSRFをやってみたいと思います。
現在は1件のリストが登録されています。
以下のHTMLファイルをブラウザで開きます。
<!DOCTYPE html> <html lang="en"> <body> <h1>悪意のあるサイト</h1> <form action="http://127.0.0.1:8000/create/" method="POST"> <input type="hidden" name="title" value="csrf悪意のある攻撃"> <input type="hidden" name="memo" value="サイト間リクエスト偽装"> <input type="hidden" name="duedate" value="2023-05-20"> <input type="hidden" name="priority" value="danger"> </form> <script> document.forms[0].submit(); </script> </body> </html>
リストが2件に増えています
今回は、ただのTodoリストなので勝手にリクエストが送られてきても大して困りませんが、これが銀行システムやECサイト、twitterなどのSNSだと考えると恐ろしいですね…
CSRFトークンを使用した対策
アプリケーションのformにトークンを設置しておき、送信する仕組みにすることで、サイト内のformからのみのアクセスを受け付けるようにすることができます。
DjangoではデフォルトでCSRFトークンの検証を行ってくれており、以下のようにPOSTメソッドのformはcsrf_tokenタグを入れるだけでOK
{% load static %} <!doctype html> <html lang="ja"> <form action="{% url XX %}" method="post"> {% csrf_token %} //csrfトークンを設置 {{ form.as_p }} <input type="submit" value="send"> </form> </html>
実際にはformタグの中に 、以下のようなinputタグが自動生成されます。
<input type="hidden" name="csrfmiddlewaretoken" value="asdfg2hhrshj45rytktytehg7tetrwhjy">
csrf_tokenがない状態でPOSTメソッドのリクエストを送ると、403エラーとなります。
まとめ
これまでセキュリティー分野に関しては、必要だと思いながらも中々とっつき辛いこともあり、手を付けられずにいました。今回、この記事をまとめる中でセキュリティー対策を怠ることの危険性を再認識しました。今後は苦手意識を持たずにセキュリティーに関しても学ぶ必要があると感じました。
参考資料
https://www.ipa.go.jp/security/vuln/websecurity/csrf.html
https://kinsta.com/jp/blog/csrf-attack/