web-dev-qa-db-ja.com

devise user sign_inは、CSRFトークン認証トークンの認証エラーを出します

devise(最新バージョン-3.2.0)とRails(最新バージョン-4.0.1)を使用しています

単純な認証(ajaxまたはapiなし)を実行していて、CSRF認証トークンのエラーが発生しています。以下のPOSTリクエストを確認してください

started POST "/users/sign_in" for 127.0.0.1 at 2013-11-08 19:48:49 +0530
Processing by Devise::SessionsController#create as HTML

 Parameters: {"utf8"=>"✓",    
 "authenticity_token"=>"SJnGhXXUXjncnPhCdg3muV2GYCA8CX2LVFV78pqddD4=", "user"=> 
{"email"=>"[email protected]", "password"=>"[FILTERED]", "remember_me"=>"0"},
"commit"=>"Sign in"}

Can't verify CSRF token authenticity
 User Load (0.4ms)  SELECT "users".* FROM "users" WHERE "users"."email" =  
'[email protected]' LIMIT 1
(0.1ms)  begin transaction
SQL (0.4ms)  UPDATE "users" SET "last_sign_in_at" = ?, "current_sign_in_at" = ?,
"sign_in_count" = ?, "updated_at" = ? WHERE "users"."id" = 2  [["last_sign_in_at", Fri,
08 Nov 2013 14:13:56 UTC +00:00], ["current_sign_in_at", Fri, 08 Nov 2013 14:18:49 UTC
+00:00], ["sign_in_count", 3], ["updated_at", Fri, 08 Nov 2013 14:18:49 UTC +00:00]]
(143.6ms)  commit transaction
Redirected to http://localhost:3000/
Completed 302 Found in 239ms (ActiveRecord: 144.5ms | Search: 0.0ms)

ルートURLはhome#newを指します。これは次のようなものです。

class HomeController < ApplicationController
   before_action :authenticate_user!
   def index
   end
end

サインインページで生成されたhtmlビューは次のようになります。

  • メタタグ

    <meta content="authenticity_token" name="csrf-param" />
    <meta content="aV+d7Z55XBJF2VtyL8V3zupR3OwhaQ6UHNtlQLBQf5Y=" name="csrf-token" />
    
  • <form accept-charset="UTF-8" action="/users/sign_in" class="new_user" id="new_user" 
    method="post">
    <div style="margin:0;padding:0;display:inline">
    <input name="utf8" type="hidden" value="&#x2713;" />
    <input name="authenticity_token" type="hidden
    value="aV+d7Z55XBJF2VtyL8V3zupR3OwhaQ6UHNtlQLBQf5Y=" />
    </div>
    <div><label for="user_email">Email</label><br />
    <input autofocus="autofocus" id="user_email" name="user[email]" type="email" value="" />
    </div>
    
    <div><label for="user_password">Password</label><br />
    <input id="user_password" name="user[password]" type="password" /></div>
    
    <div><input name="user[remember_me]" type="hidden" value="0" />
    <input id="user_remember_me" name="user[remember_me]" type="checkbox" value="1" /> 
    <label for="user_remember_me">Remember me</label></div>
    
    <div><input name="commit" type="submit" value="Sign in" /></div>
    </form>
    

認証要求はlast_sign_in_atsign_in_countの値も更新しますが、コントローラーでcurrent_userにアクセスしようとすると、nilとして表示されます。

私によると、実際にはuserにサインインしていません。しかし、「なぜuserテーブルのlast_sign_in_at/sign_in_count値を更新するのですか?」という質問があります。

19
rtcoms

Devisegemに問題はありませんでした。 「Rails-api」gemを削除すると、アプリが機能し始めました。

2
rtcoms

CSRFトークンが正しくない場合、Railsはセッションの読み取りや更新を行いません。コントローラーが指定する他のアクションは引き続き実行されます。これにより、DBの更新が表示されるのに、実行されない理由が説明されます。ログインしてしまうことはありません。

ログとページのauthenticity_tokenが一致していないことに気付きました。これは、別のリクエストをキャプチャしたことが原因である可能性があることを認識していますが、ページ上のものが同じリクエストのログ内のものと一致することを確認する必要があります。また、ビューで適切なタグを使用していて、毎回異なるauthenticity_tokenを生成し、HTML入力をハードコーディングしているだけではないと想定しています。

考案とは関係のないフォームでも同じ問題が発生しますか?そうでない場合は、回避策として、コントローラーで次のコードを使用して、アクションをCSRFチェックから除外できます。

protect_from_forgery except: :sign_in

サインインアクションに対するCSRF攻撃の可能性は、私にはかなり遠い(<-pun)ようです。

また、それがデバイスだけの場合は、問題を報告することをお勧めします すでに行っています

10
Jason Barnabe

これをアプリケーションコントローラーに追加します(これはRails 5)で機能します)

protect_from_forgery unless: -> { request.format.json? }

これをDeviseSessionControllerに追加します

skip_before_action :verify_authenticity_token, only: [:create]

カールでお試しください

curl -X POST -v -H 'Content-Type: application/json' http://0.0.0.0:3000/users/sign_in -d '{"user" : {"email": "[email protected]", "password": "secret" }}'
4
Roberto Brvé

ビューの「remote:true」オプションを削除するだけで同じ問題を修正しました:form_for(model、remote:true)をform_for(model)に変更しました

0
guest