@Jxckさんの記事を読んで、現代におけるCSRF対策を学んだ blog.jxck.io
記事の趣旨は、Cookie が SameSite Lax by Default になったので「CSRF」は古の攻撃になったのか、何もしなくていいのかという話
CSRFの問題は「攻撃者の form からのリクエストにも SNS の Cookie が付与されるから」だったので、SameSite=Laxがデフォルト設定になることによって防ぐことができるようになった
ただ、SameSite Cookie だけに依存した対策は、サブドメインが SameSite であることを理由に攻撃が可能である
なのでこれはあくまで二次防御的な対策で、「リクエストの Origin が意図したものであるかをチェックする」という一次防御が必要とのこと
現代における意図したOrigin であるかのチェック
副作用のあるエンドポイントのチェックのやり方
- POST にする
- Origin を確認する
- SameSite Lax/Strict を明示する
- Fetch Metadata も確認する
記事にあった実装を拝借すると以下のようになる
app.use((req, res, next) => { // post である場合は origin と sec-fetch-site をチェック if (req.method === "post") { // origin は必ずチェック if (req.headers.origin !== "https://sns.example") { return res.send(400) } // sec-fetch-site は、存在した場合だけチェック if (req.headers.secFetchSite && req.headers.secFetchSite !== "same-origin") { return res.send(400) } } return next() }) // デフォルトに頼らず Cookie に Lax を明示 // 理想は read と write に cookie を分け write を Strict にする app.use(session("Lax")) // 副作用のある API は必ず POST にする app.post("/post", async (req, res) => { await createPost(req.body) // ... })
トークンによるCSRF対策は必要か?
SameSite Lax by Default の以前はトークンによるCSRF対策を行なっていた
これは今でも必要かというと、実装はだいぶこなれていて堅牢であるのも確かだが、一次防御がなされていればこそなので、これも多層防御の二層目という認識を持つべき
CSRF対策はアップデートできてなく、何も考えずにトークンで対策していた
今の時代にプラットフォームが用意しているものを生かして対策を考えたい