【问题标题】:protect_from_forgery does not protect PUT/DELETE requestsprotect_from_forgery 不保护 PUT/DELETE 请求
【发布时间】:2015-07-23 01:21:24
【问题描述】:

我使用rails new demo 制作了一个演示应用程序,然后使用rails generate scaffold User name:string email:string 生成了一个脚手架用户控制器。脚手架代码有一个ApplicationControllerprotect_from_forgeryUserController 也是如此,它派生自ApplicationController

我运行 webrick,添加一个用户,很酷。真实性令牌与 /users 上的 POST 一起使用。

但我仍然可以使用 Rails 3.0.5:

niedakh@twettek-laptop:~$ telnet 10.0.0.4 3000
PUT /users/3 HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 39

user[name]=vvvvv&user[email]=shiaus.pl

并且在不提供令牌的情况下修改用户 3:

Started PUT "/users/3" for 10.0.0.4 at 2011-04-02 14:51:24 +0200
  Processing by UsersController#update as HTML
  Parameters: {"user"=>{"name"=>"vvvvv", "email"=>"shiaus.pl\r"}, "id"=>"3"}
  User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 3 LIMIT 1
', "updated_at" = '2011-04-02 12:51:24.437267' WHERE "users"."id" = 3s.pl
Redirected to http://10.0.0.4:3000/users/3
Completed 302 Found in 92ms

我也可以用 DELETE 做同样的事情:

DELETE /users/3 HTTP/1.1

这给了我:

Started DELETE "/users/3" for 10.0.0.4 at 2011-04-02 15:43:30 +0200
  Processing by UsersController#destroy as HTML
  Parameters: {"id"=>"3"}
  SQL (0.7ms)   SELECT name
 FROM sqlite_master
 WHERE type = 'table' AND NOT name = 'sqlite_sequence'

  User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 3 LIMIT 1
  AREL (0.5ms)  DELETE FROM "users" WHERE "users"."id" = 3

Redirected to http://10.0.0.4:3000/users
Completed 302 Found in 180ms

您能否向我解释一下,当我从不随这些请求发送任何令牌时,为什么我可以做这些事情?

【问题讨论】:

    标签: ruby-on-rails http put http-delete protect-from-forgery


    【解决方案1】:

    非常短的版本protect_from_forgery 旨在防止来自伪造 HTML FORM 元素的 XSRF 攻击。 PUT 和 DELETE 不易受到 XSRF 攻击,因为 HTML 表单不能使用 PUT 或 DELETE。

    XSRF(跨站请求伪造)攻击是指受害者浏览器在没有用户交互的情况下被欺骗向服务器提交伪造请求。

    加长版:您能够做到这一点的原因是您:

    • 不需要安全/登录,或者
    • 已登录并正在从托管在同一域上的脚本发出请求,或者
    • 正在通过 Fiddler 或类似工具发出请求(绕过浏览器的内置保护)。

    这些不是protect_from_forgery 旨在防止的场景。

    protect_from_forgery 的目的是防止 XSRF 攻击 - 跨站点请求伪造。当访问恶意网站(或添加了恶意的好网站)的用户被诱骗向另一个网站提交请求时,就会发生这种情况。例如,您可以欺骗访问者发出任何 GET 请求,如下所示:

    <img src="http://victim.com/victimPage?action=delete&id=ID12345" />
    

    只要受害者访问 Evil 网站,他的浏览器就会自动尝试检索图像。这显然不会检索图像,但同时victim.com 将执行删除项目ID12345 的请求。 POST可以用类似的方式伪造,只需创建一个表单,然后使用脚本将其提交到外部站点,或者诱使用户点击提交。

    这就是protect_from_forgery 的用武之地:服务器在表单的隐藏字段中将令牌发送给客户端。如果没有出现有效的令牌,服务器会断定提交的表单不是服务器发送的真实表单的提交,因此请求被拒绝,因为可能是伪造的。

    但你知道的。

    重点是 HTTP 表单只能使用 GET 和 POST 方法,不能使用 PUT 或 DELETE。这有两个效果:

    • 首先,如果您收到 PUT 或 DELETE,则无法放置 protect_from_forgery 令牌。 PUT 或 DELETE 不是表单提交的结果,因此服务器无法将令牌发送给客户端,因此客户端没有令牌可发送回。
    • 其次,由于 HTML 表单只能使用 POST 和 GET,如果请求是 PUT 或 DELETE,则攻击者无法使用 HTML 表单来强制或欺骗用户提交请求。他们可以使用 XMLHttpRequest,但 XMLHttpRequest 不允许跨站点请求(除非由两个站点的安全设置启用)。

    这意味着,如果您托管它的域本身不包含恶意代码,则无需保护 PUT 和 DELETE 免受伪造。如果服务器确实包含恶意代码,攻击者可以发出任意 XMLHttpRequest 请求以获取有效令牌,从而轻松绕过伪造保护。

    有关 XSRF 的简要说明,请点击此处:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-03-10
      • 1970-01-01
      • 1970-01-01
      • 2015-07-10
      • 2019-04-21
      • 1970-01-01
      • 2015-05-17
      • 2013-12-06
      相关资源
      最近更新 更多