Edited at

【Rails】個人的に思いついた二重サブミット対策【意見も募集】


二重サブミットをどうにか防止したかった。

具体的には下記のようなケースで防止したかったです。

- ブラウザバックか戻るボタンで戻って、再度保存

- 完了ページでブラウザリロード

参考:さいきょうの二重サブミット対策


contorllerの処理


inquiries_controller.rb

  def new

@inquiry = Inquiry.new
end

def confirm
@inquiry = Inquiry.new(inquiry_params)
render :new unless @inquiry.valid?
end

def done
@inquiry = Inquiry.new(inquiry_params)

if params[:back].present?
render :new
return
end

if @inquiry.save
#メールを送付
InquiryMailer.send_inquiry_to_user(@inquiry).deliver
else
render :new
end

end


入力画面▶️確認画面▶️完了画面の順に移り変わります。

確認画面と完了画面に関してはPostで表示させています。

完了画面にリダイレクトさせるPRGパターンもあるようですが、今回は採用していません。


個人的に思いついた二重サブミット対策

完了画面のPost処理の最後にセッションのauthenticity_tokenのパラメータを削除する。

session[:_csrf_token] = nil

RailsはデフォルトでCSRF対策をしてくれます。

class ApplicationController < ActionController::Base

protect_from_forgery with: :exception
end

上記によってファームを生成する際にauthenticity_tokenがフォームとセッションに発行され、その二つが合っているかを判断します。

よってPostの最後にセッション側のトークンを削除することで、以降フォームとセッションのトークン情報が合致しなくなるためリロードやブラウザバックをしてもInvalidAuthenticityTokenとしてエラーになります。これで二重サブミットの対策になるんじゃないかと。(InvalidAuthenticityTokenの場合のエラーページを表示させるようにすればユーザーも戸惑わないはず)

セッションのトークンを削除することによるCSRF対策の影響も恐らくないのではと。

参考:RailsでのCSRFtoken発行/検証のロジック


最後に

まだまだRailsに関しては初心者で、他の方法が思いつかなかったので他の人は普段どうやって実装しているのか知りたいです!!!!!!

ぜひ教えてください!!!!!!!!!!!!