【问题标题】:Rails 3: CSRF with form_tagRails 3:带有 form_tag 的 CSRF
【发布时间】:2013-12-12 02:02:09
【问题描述】:

快速背景

我有一个模型,其中 facility has_many managersrelationships。关系模型包含一个附加属性admin,它是一个布尔值。然后,对于每个设施,我都有一个页面,允许管理员/某些用户将managers 标记为admin 或不标记。他们通过复选框来做到这一点。我正在为经理使用设计。就像这个 railscast 的前 2 分钟一样,一切都差不多完成了:

http://railscasts.com/episodes/165-edit-multiple-revised?view=comments

问题

问题是,当我提交 form_tag 时,我得到:

1. 警告:无法验证 CSRF 令牌的真实性

2. 然后它会重置我的用户会话(让我退出设备),所以我必须重新登录才能继续工作。

如果我从应用程序控制器中删除 protect from forgery,一切都会顺利进行,但显然我不想这样做。

那么,如何避免 form_tag 出现这个 CSFR 问题?

表格(更新)

<%= form_tag admin_relationships_path, method: :put do %>
  <table>
    <tr>
    <th></th>
    <th>Person Name</th>
    <th>Admin</th>
    </tr>

<% @relationships.each do |relationship| %>
   <tr>
   <td><%= check_box_tag "relationship_ids[]", relationship.id %></td>
   **<%= hidden_field_tag :authenticity_token, form_authenticity_token %>**        
   <td><%= User.find(relationship.user_id).full_name %></td>
   <td><%= relationship.admin ? "Yes" : "No" %></td>

   <td><%= link_to 'Remove', relationship, method: :delete, **remote: true** %></td>

   </tr>
 <% end %>
  </table>

   <%= submit_tag "Make Checked Admins" %>
 <% end %>

控制器。

class RelationshipsController < ApplicationController

  def destroy
    @relationship = Relationship.find(params[:id])
    @relationship.destroy

    respond_to do |format|
      format.html { redirect_to "/facilities/1679/invite", notice: " Manager has been deleted." }
      format.json { head :no_content }
  end
end

日志。

Started DELETE "/relationships/52" for 127.0.0.1 at 2013-11-26 14:30:11 -0500
Processing by RelationshipsController#destroy as JS
Parameters: {"id"=>"52"}
WARNING: Can't verify CSRF token authenticity
  User Load (0.3ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 38 LIMIT 1
  (0.1ms)  BEGIN
  (0.1ms)  COMMIT
 Relationship Load (0.2ms)  SELECT `relationships`.* FROM `relationships` WHERE `relationships`.`id` = 52 LIMIT 1
  (0.1ms)  BEGIN
 SQL (0.2ms)  DELETE FROM `relationships` WHERE `relationships`.`id` = 52
  (0.4ms)  COMMIT
 Redirected to http://localhost:3000/facilities/1679/invite
 Completed 302 Found in 10ms (ActiveRecord: 1.6ms)


 Started DELETE "/facilities/1679/invite" for 127.0.0.1 at 2013-11-26 14:30:11 -0500

 ActionController::RoutingError (No route matches [DELETE] "/facilities/1679/invite"):

请求标头:

AcceptAccept-EncodingAccept-LanguageConnectionCookieHostOriginRefererUser-AgentX-Requested-With

答案

正如下面的海报所提到的,我的 CSFR 令牌没有在页面上收到。虽然,我的应用程序布局和管理布局中有&lt;%= csrf_meta_tag %&gt;,但我实际上是在渲染应用程序布局,但表单位于设计页面上。

所以我需要将&lt;%= csrf_meta_tag %&gt; 代码放在devise.html.erb. 中,您可以在下面找到故障排除。

【问题讨论】:

    标签: ruby-on-rails devise csrf


    【解决方案1】:

    确保您的应用程序布局中的 head 部分中有此内容:

    <%= csrf_meta_tag %>
    

    或者表单中的这个隐藏字段:

    <%= hidden_field_tag :authenticity_token, form_authenticity_token %>
    

    【讨论】:

    • &lt;%= hidden_field_tag :authenticity_token, form_authenticity_token %&gt; 成功了。谢谢。
    • csrf_meta_tag 用于 Ajax 请求。如果你使用 Rails 表单助手,它应该自动添加authentity_token 字段。
    • 其实我可能接受得太快了。这些解决方案适用于管理操作,但不适用于删除操作。
    • 尝试对删除操作使用 remote: true 以使其使用 ajax,这样它就可以获取 csrf 元标记
    • 仍然退出登录,我添加了控制器操作、日志和使用上面的远程 true 的新表单。
    【解决方案2】:

    尝试将其添加到 aplication.js:

    $.ajaxSetup({
      headers: {
        'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
      }
    });
    

    在这里回答:WARNING: Can't verify CSRF token authenticity rails

    【讨论】:

    • 还是不行,是不是也需要加上 before send 方法?顺便说一句,我每次都在重新启动服务器。
    • 不,要么是要么。你用的是什么版本的 Rails?如果您使用的是 3.1,请尝试以下答案:stackoverflow.com/questions/7203304/…
    • 我不知道问题出在哪里。那也行不通。该应用使用 3.2.11。
    • 另外,我注释掉了protect from forgery 只是为了看看一切是否顺利。我使用 remote: true 添加的 Ajax 链接在单击后就坐在那里,我必须重新加载页面才能看到从列表中删除的已删除项目。所以也许js没有被接受或其他什么。
    • 您能否进入您的网络检查器(例如 firebug)的网络选项卡并查看单击删除链接时的请求标头是什么?确保有 X-CSRF-Token 的标头。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-13
    • 1970-01-01
    • 2011-06-18
    • 1970-01-01
    • 2014-01-09
    • 2016-05-06
    相关资源
    最近更新 更多