Ruby-on-rails Rails:发出 POST 请求时无法验证 CSRF 令牌的真实性

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35181340/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 00:22:35  来源:igfitidea点击:

Rails: Can't verify CSRF token authenticity when making a POST request

ruby-on-rails

提问by cqcn1991

I want to make POST requestto my local dev, like this:

我想为POST request我的本地开发人员制作,如下所示:

  HTTParty.post('http://localhost:3000/fetch_heroku',
                :body => {:type => 'product'},)

However, from the server console it reports

但是,它从服务器控制台报告

Started POST "/fetch_heroku" for 127.0.0.1 at 2016-02-03 23:33:39 +0800
  ActiveRecord::SchemaMigration Load (0.0ms)  SELECT "schema_migrations".* FROM "schema_migrations"
Processing by AdminController#fetch_heroku as */*
  Parameters: {"type"=>"product"}
Can't verify CSRF token authenticity
Completed 422 Unprocessable Entity in 1ms

Here is my controller and routes setup, it's quite simple.

这是我的控制器和路由设置,非常简单。

  def fetch_heroku
    if params[:type] == 'product'
      flash[:alert] = 'Fetch Product From Heroku'
      Heroku.get_product
    end
  end

  post 'fetch_heroku' => 'admin#fetch_heroku'

I'm not sure what I need to do? To turn off the CSRF would certainly work, but I think it should be my mistake when creating such an API.

我不确定我需要做什么?关闭CSRF当然可以,但我认为在创建这样的API时应该是我的错误。

Is there any other setup I need to do?

我需要做任何其他设置吗?

回答by max

Cross site request forgery (CSRF/XSRF) is when a malicious web page tricks users into performing a request that is not intended for example by using bookmarklets, iframes or just by creating a page which is visually similar enough to fool users.

跨站点请求伪造 (CSRF/XSRF) 是指恶意网页通过使用书签、iframe 或仅通过创建一个视觉上足够相似的页面来欺骗用户执行不打算执行的请求以欺骗用户。

The Rails CSRF protectionis made for "classical" web apps - it simply gives a degree of assurance that the request originated from your own web app. A CSRF token works like a secret that only your server knows - Rails generates a random token and stores it in the session. Your forms send the token via a hidden input and Rails verifies that any non GET request includes a token that matches what is stored in the session.

Rails的CSRF保护作出了“经典” Web应用程序-它只是给出了一个程度的保证了请求源于自己的Web应用程序。CSRF 令牌就像一个只有你的服务器知道的秘密——Rails 生成一个随机令牌并将其存储在会话中。您的表单通过隐藏输入发送令牌,Rails 会验证任何非 GET 请求是否包含与会话中存储的内容相匹配的令牌。

However an API is usually by definition cross site and meant to be used in more than your web app, which means that the whole concept of CSRF does not quite apply.

然而,根据定义,API 通常是跨站点的,并且不仅仅用于您的 Web 应用程序,这意味着 CSRF 的整个概念并不完全适用。

Instead you should use a token based strategy of authenticating API requests with an API key and secret since you are verifying that the request comes from an approved API client - not from your own app.

相反,您应该使用基于令牌的策略,通过 API 密钥和密钥对 API 请求进行身份验证,因为您要验证请求来自已批准的 API 客户端 - 而不是来自您自己的应用程序。

You can deactivate CSRF as pointed out by @dcestari:

正如@dcestari 所指出的,您可以停用 CSRF:

class ApiController < ActionController::Base
  protect_from_forgery with: :null_session
end

Updated.In Rails 5 you can generate API only applications by using the --apioption:

更新。在 Rails 5 中,您可以使用以下--api选项生成仅 API 的应用程序:

rails new appname --api

They do not include the CSRF middleware and many other components that are superflouus.

它们不包括 CSRF 中间件和许多其他多余的组件。

回答by Matt Waldron

Another way to turn off CSRF that won't render a null session is to add:

关闭不会呈现空会话的 CSRF 的另一种方法是添加:

skip_before_action :verify_authenticity_token

in your Rails Controller. This will ensure you still have access to session info.

在您的 Rails 控制器中。这将确保您仍然可以访问会话信息。

Again, make sure you only do this in API controllers or in other places where CSRF protection doesn't quite apply.

同样,请确保您只在 API 控制器或其他不完全适用 CSRF 保护的地方执行此操作。

回答by Mr. Tao

There is relevant info on a configuration of CSRF with respect to API controllers on api.rubyonrails.org:

关于api.rubyonrails.org上的 API 控制器的 CSRF 配置有相关信息:

?

It's important to remember that XML or JSON requests are also affected and if you're building an APIyou should change forgery protection method in ApplicationController(by default: :exception):

class ApplicationController < ActionController::Base
  protect_from_forgery unless: -> { request.format.json? }
end

We may want to disable CSRF protection for APIs since they are typically designed to be state-less. That is, the request APIclient will handle the session for you instead of Rails.

?

?

重要的是要记住 XML 或 JSON 请求也会受到影响,如果您正在构建API,您应该在ApplicationController(默认情况下:)更改伪造保护方法:exception

class ApplicationController < ActionController::Base
  protect_from_forgery unless: -> { request.format.json? }
end

我们可能希望禁用 API 的 CSRF 保护,因为它们通常被设计为无状态的。也就是说,请求API客户端将为您而不是 Rails 处理会话。

?

回答by webaholik

In Rails 5 you can also create a new class with ::APIinstead of ::Base:

在 Rails 5 中,您还可以使用::API而不是 ::Base创建一个新类:

class ApiController < ActionController::API
end

回答by Ryosuke Hujisawa

If you want to exclude the sample controller's sample action

如果要排除示例控制器的示例操作

class TestController < ApplicationController
  protect_from_forgery :except => [:sample]

  def sample
     render json: @hogehoge
  end
end

You can to process requests from outside without any problems.

您可以毫无问题地处理来自外部的请求。

回答by Arish Khan

The simplest solution for the problem is do standard things in your controller or you can directely put it into ApplicationController

这个问题最简单的解决方案是在你的控制器中做标准的事情,或者你可以直接把它放到ApplicationController 中

class ApplicationController < ActionController::Base protect_from_forgery with: :exception, prepend: true end

class ApplicationController < ActionController::Base protect_from_forgery with: :exception, prepend: true end