Rails 中 Thread.current[] 使用的安全性

发布于 2024-12-11 22:07:34 字数 984 浏览 0 评论 0 原文

对于在 Thread.current 哈希中存储信息(例如,current_user、当前子域等)的做法,我不断收到相互矛盾的意见。该技术被提议作为一种简化模型层内后续处理(查询范围、审核等)的方法。

许多人认为这种做法不可接受,因为它破坏了 MVC 模式。 其他人对该方法的可靠性/安全性表示担忧,我的由两部分组成的问题集中在后一个方面。

  1. Thread.current 哈希值是否保证在其整个周期内对一个且仅一个响应可用且私有?

  2. 据我了解,线程在响应结束时很可能会被移交给其他传入请求,从而泄漏 Thread.current 中存储的任何信息。在响应结束之前清除此类信息(例如,通过从控制器的 after_filter 执行 Thread.current[:user] = nil)足以防止此类安全漏洞吗?< /p>

谢谢! 朱塞佩

I keep getting conflicting opinions on the practice of storing information in the Thread.current hash (e.g., the current_user, the current subdomain, etc.). The technique has been proposed as a way to simplify later processing within the model layer (query scoping, auditing, etc.).

Many consider the practice unacceptable because it breaks the MVC pattern.
Others express concerns about reliability/safety of the approach, and my 2-part question focuses on the latter aspect.

  1. Is the Thread.current hash guaranteed to be available and private to one and only one response, throughout its entire cycle?

  2. I understand that a thread, at the end of a response, may well be handed over to other incoming requests, thereby leaking any information stored in Thread.current. Would clearing such information before the end of the response (e.g. by executing Thread.current[:user] = nil from a controller's after_filter) suffice in preventing such security breach?

Thanks!
Giuseppe

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

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

发布评论

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

评论(4

痕至 2024-12-18 22:07:34

没有特定的理由远离线程局部变量,主要问题是:

  • 时必须记住设置线程局部变量类
  • 测试它们更困难,因为在测试使用它的代码 使用线程局部变量需要知道这些对象对它们来说不可用,而是在线程局部变量内,并且这种间接通常会破坏demeter 定律
  • 如果您的框架重用线程,则不清理线程局部变量可能会成为一个问题(线程局部变量已经启动并且代码依赖于 ||=< /strong> 调用初始化变量可能会失败

因此,虽然它并不是完全不可能使用,但最好的方法是不使用它们,但时不时你会遇到线程本地化的问题将是最简单的解决方案,无需进行大量更改代码,你将不得不妥协,有一个不太完美的面向对象模型与线程本地或改变相当多的代码来做同样的事情。

因此,这主要是一个思考问题,哪个将是适合您的情况的最佳解决方案,如果您真的要走线程本地路径,我肯定会建议您使用记住在之后清理的块来执行此操作它们已完成,如下所示:

around_filter :do_with_current_user

def do_with_current_user
    Thread.current[:current_user] = self.current_user
    begin
        yield
    ensure
        Thread.current[:current_user] = nil
    end      
end

如果该线程被回收,这可确保线程局部变量在使用之前被清理。

There is not an specific reason to stay away from thread-local variables, the main issues are:

  • it's harder to test them, as you will have to remember to set the thread-local variables when you're testing out code that uses it
  • classes that use thread locals will need knowledge that these objects are not available to them but inside a thread-local variable and this kind of indirection usually breaks the law of demeter
  • not cleaning up thread-locals might be an issue if your framework reuses threads (the thread-local variable would be already initiated and code that relies on ||= calls to initialize variables might fail

So, while it's not completely out of question to use, the best approach is not to use them, but from time to time you hit a wall where a thread local is going to be the simplest possible solution without changing quite a lot of code and you will have to compromise, have a less than perfect object oriented model with the thread local or changing quite a lot of code to do the same.

So, it's mostly a matter of thinking which is going to be the best solution for your case and if you're really going down the thread-local path, I'd surely advise you to do it with blocks that remember to clean up after they are done, like the following:

around_filter :do_with_current_user

def do_with_current_user
    Thread.current[:current_user] = self.current_user
    begin
        yield
    ensure
        Thread.current[:current_user] = nil
    end      
end

This ensures the thread local variable is cleaned up before being used if this thread is recycled.

梓梦 2024-12-18 22:07:34

这个小宝石确保您的线程/请求局部变量不会粘在请求之间: https://github.com/steveklabnik/request_store< /a>

This little gem ensures your thread/request local variables not stick between requests: https://github.com/steveklabnik/request_store

猫烠⑼条掵仅有一顆心 2024-12-18 22:07:34

接受的答案涵盖了这个问题,但Rails 5现在提供了一个“抽象超类”ActiveSupport::CurrentAttributes 使用 Thread.current。

我想我会提供一个链接作为可能的(不受欢迎)解决方案。

https://github.com/rails/rails/blob /master/activesupport/lib/active_support/current_attributes.rb

The accepted answer covers the question but as Rails 5 now provides a "Abstract super class" ActiveSupport::CurrentAttributes which uses Thread.current.

I thought I would provide a link to that as a possible(unpopular) solution.

https://github.com/rails/rails/blob/master/activesupport/lib/active_support/current_attributes.rb

落叶缤纷 2024-12-18 22:07:34

接受的答案在技术上是准确的,但正如答案中温和指出的那样,以及 http ://m.onkey.org/thread-safety-for-your-rails 不太温和:

不要使用线程本地存储,Thread.current 如果你不这样做绝对不必

request_store 是另一个解决方案(更好),但只需阅读自述文件即可了解更多留下来的理由远离线程本地存储。

几乎总有更好的方法。

The accepted answer is technically accurate, but as pointed out in the answer gently, and in http://m.onkey.org/thread-safety-for-your-rails not so gently:

Don't use thread local storage, Thread.current if you don't absolutely have to

The gem for request_store is another solution (better) but just read the readme there for more reasons to stay away from thread local storage.

There is almost always a better way.

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