この記事を読んでできること
CSRFトークンの実装ができる
やりたいこと
ログイン認証機能がないパブリックサイトでクライアントへのCSRFトークンの付与と認証をstarlette-csrfというライブラリで実装する
記述しないこと
- FastAPIの実装について
- Cookieについて
使用技術
バックエンド
- 言語
- Python 3.10.4
- フレームワーク
- Fast API 0.78.0
- 使用ライブラリ
- starlette-csrf==1.4.4
※
トークンを発行して認証するシステムは完全にstarlette-csrfというライブラリに任せます
発行と認証の流れ(フロントとの疎通)
- GETメソッドでトークンを発行するAPIをフロントエンドに叩いてもらう
- クライアントのCookieファイルに
csrftoken
というkeyでランダム文字列のトークンが格納される - リクエスト毎にクライアントから
x-csrftoken
というkeyでヘッダーを送ってもらう - ライブラリで最初に発行したものと一致するか確認し、問題がなければリクエストを通す
実装例
main.py
import os
from fastapi import FastAPI
from starlette_csrf import CSRFMiddleware
from routers import router
app = FastAPI()
app.add_middleware(
CSRFMiddleware,
secret=os.environ["SECRET_KEY"],
)
app.include_router(router.router)
routers/router.py
@router.get("/api/get_csrf_token", tags=["token"])
def get_csrf_token():
return "トークンを発行しました。"
starlette-csrfについての詳細
starlette-csrfの仕様
- 安全なhttpメソッド(GET, HEAD, OPTIONS, TRACE)でリクエストされたとき、set-cookieでクライアントのcookieにcsrftokenというkeyで格納する
- クライアントからPOSTリクエストされたとき、x-csrftokenというkeyでcookie headerが送信されることを期待する
- cookieとheaderのtokenの値を比較検証する
- それらが一致した場合、リクエストは処理される
- 一致しない場合は、403 Forbiddenエラー応答が返される
Cookie属性
READMEに詳細記載あり
cookieの名前やパス、Secure属性、Samesite属性を変更することができる
処理の検証結果
- 現状、単純なapi/get_csrf_tokenというエンドポイントを作成し、tokenをセットする
- POSTMANで
- ヘッダにx-csrftokenを用意しない場合は、403エラー
- ヘッダにx-csrftokenを用意したが、valueが一致しない場合も403エラー
- ヘッダにx-csrftokenを用意し、valueが一致した場合、リクエストを処理する