Protect_from_forgery 不保护 PUT/DELETE 请求

发布于 2024-10-29 14:40:42 字数 1658 浏览 5 评论 0原文

我使用rails new demo制作了一个演示应用程序,然后使用rails生成脚手架用户名:字符串电子邮件:字符串生成了一个脚手架用户控制器。脚手架代码有一个带有 protect_from_forgeryApplicationController,派生自 ApplicationControllerUserController 也是如此。

我运行 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

你能向我解释一下为什么我可以在以下情况下执行这些操作吗?我从来没有在这些请求旁边发送任何令牌?

I made a demo application with rails new demo and then generated a scaffolded user controller with rails generate scaffold User name:string email:string. The scaffolded code has an ApplicationController with protect_from_forgery, so does UserController which derives from ApplicationController.

I run webrick, add a user, cool. Authenticity token works as promised with the POST on /users.

Yet still with Rails 3.0.5 I am able to do a:

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

And have the user 3 modified without giving a token:

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

Also I can do the same with DELETE:

DELETE /users/3 HTTP/1.1

Which gives me:

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

Could you explain to me why can I do those things when I never send any token alongside those requests?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

┊风居住的梦幻卍 2024-11-05 14:40:42

非常简短的版本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" />

一旦受害者访问邪恶站点,他的浏览器就会自动尝试检索图像。这显然不会检索到图像,但同时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 的快速描述,请尝试此处:

Very Short Version: protect_from_forgery is designed to protect against XSRF attacks from forged HTML FORM elements. PUT and DELETE are not vulnerable to XSRF attacks because HTML forms cannot use PUT or DELETE.

An XSRF (cross site request forgery) attack is where the victim browser is tricked into submitting a forged request to the server without interaction from the user.

Longer version: The reason you are able to do this is you either:

  • Have no security/login required, or
  • Have already logged in and are making the requests from script hosted on the same domain, or
  • Are making the requests via Fiddler or similar, (bypassing the browser's built-in protections).

These are not the scenario protect_from_forgery is designed to protect against.

The purpose of the protect_from_forgery is to protect against XSRF attacks - Cross Site Request Forgery. This occurs when a user visiting an evil website (or a good website with added evil) is tricked into submitting a request to another website. For example you can trick a visitor into making any GET request, like this:

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

As soon as the victim visits the Evil site, his browser will automatically attempt to retrieve the image. This will obviously not retrieve an image, but meanwhile victim.com will execute the request deleting item ID12345. POST can be forged in a similar way, just create a form, and submit it to the foreign site using script, or else trick the user into clicking on it to submit.

That is where protect_from_forgery comes in: The server sends the token to the client in a hidden field with the form. If no valid token appears, the server concludes that the form which was submitted isn't a submission of a genuine form sent by the server, so the request is rejected as potentially forged.

But you knew that.

The point is that HTTP forms can only use methods GET and POST, not PUT or DELETE. This has two effects:

  • First, if you get a PUT or DELETE, there is nowhere to put the protect_from_forgery token. PUT or DELETE are not the result of a form submitting, so there is no way for the server to send the token to the client, therefore the client has no token to send back.
  • Second, since HTML forms can only use POST and GET, if the request is a PUT or DELETE the attacker cannot use a HTML form to force or trick the user into submitting the request. They can use XMLHttpRequest, but XMLHttpRequest does not allow cross-site requests (unless enabled by security settings on both sites).

This means that, provided the domain you host it on does not contain evil code itself, it is not necessary to protect PUT and DELETE from forgery. If the server does contain evil code, the attacker can make arbitrary XMLHttpRequest requests to get a valid token, and therefore easily circumvent the forgery protection anyway.

For a quick description of XSRF try here:

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文