【Rails】【React】API開発の際のPOSTエラー [Can't verify CSRF token authenticity.]
直面したエラー
サーバー側をAPI化し、フロント側をReactでPOST機能を実装する際におきたエラーに直面しました。
なぜかPOSTができずに原因がしばらくわかりませんでしたが、ターミナルにて以下のエラーが表示されていることに気づきました。
Started POST "/api/v1/events" for ::1 at 2022-02-24 19:50:39 +0900
Processing by Api::V1::EventsController#create as HTML
(省略)
Can't verify CSRF token authenticity. ///エラー文
Completed 401 Unauthorized in 1ms (ActiveRecord: 0.0ms | Allocations: 277)
・
・
・
原因特定
まずはお馴染みのDeepLでエラーの意味を確認。
Can't verify CSRF token authenticity.
*CSRF トークンの信頼性を確認できません。
このエラー文をgoogleで検索すると以下の記事を発見
→ https://midorimici.com/posts/rails-api-csrf
またCSRFについて曖昧だったので
→ https://yamory.io/blog/about-csrf/
これらの記事によれば簡単に言うと、
-
CSRFはユーザーが意図しない通信リクエストと処理を実行させる脆弱性を利用した攻撃方法
ex)プロフィールを更新し、送信するボタンを決済するボタンへすり替える -
Rails の場合、クライアントとの間で CSRF Token をやりとりして安全性を確認している
-
しかしRailsAPIモードだとその様な機能が無い
-
CSRF対策はサーバー側とクライアント側で設定可能
問題解決
今回はクライアント側で設定します。
///App.js///
import { csrfToken } from '@rails/ujs'; //①
axios.defaults.headers.common['X-CSRF-Token'] = csrfToken(); //②
(省略)
const createEvent = () => {
axios.post('api/v1/events', { //③
event: {
title: title,
①RailsのCSRFトークン認証に使用するため
rails-ujs ・・・ Railsの一部のRESTfulな動作や非同期な処理などを実現するために、JavaScriptの送信に関する処理などが書かれたライブラリ
参照)https://www.inodev.jp/entry/2019/12/03/234210
②csrf-tokenが自動でリクエストヘッダーに入るよう設定
Request header (リクエストヘッダー) ・・・ リクエストヘッダーは、 HTTP リクエストで使用される HTTP ヘッダーであり、メッセージの内容には関連しないものです。 Accept, Accept-, If- などのリクエストヘッダーは、条件付きリクエストを行うことができます。
参照)https://developer.mozilla.org/ja/docs/Glossary/Request_header
③POSTリクエストなどをする前にヘッダにRails側から取得したTokenを設定する
これにてPOSTリクエストをすると、、、
Started POST "/api/v1/events" for ::1 at 2022-02-25 19:26:01 +0900
Processing by Api::V1::EventsController#create as HTML
(省略)
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
Started GET "/" for ::1 at 2022-02-25 19:26:01 +0900
(2.3ms) BEGIN
↳ app/controllers/api/v1/events_controller.rb:14:in `create'
Event Create (3.6ms) INSERT INTO "events" ("user_id", "title", "content", "start", "end", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING "id"
無事投稿できました!!
参考
Discussion