1

我制作了一个演示应用程序,rails new demo然后生成了一个脚手架用户控制器rails generate scaffold User name:string email:string。脚手架的代码有一个ApplicationControllerwith protect_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

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

4

1 回答 1

11

非常简短的版本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 的快速描述,请尝试此处:

于 2011-04-09T17:07:47.970 回答