protect_from_forgery不保护PUT / DELETE请求

时间:2011-04-02 13:47:49

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

我使用rails new demo创建了一个演示应用程序,然后使用rails generate scaffold User name:string email:string生成了一个脚手架用户控制器。脚手架代码的ApplicationControllerprotect_from_forgeryUserController的{​​{1}}也是ApplicationController

我运行webrick,添加用户,很酷。真实性令牌的工作方式与/ on上的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

你能解释一下,当我从未发送过这些请求的任何令牌时,为什么我可以做这些事情?

1 个答案:

答案 0 :(得分:10)

非常短版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的快速说明,请尝试此处: