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

Giu*_*ppe 78 ruby-on-rails thread-safety

我对在Thread.current哈希中存储信息的实践(例如,current_user,当前子域等)持续存在冲突的看法.已经提出该技术作为简化模型层内的后续处理的方法(查询范围,审计等).

许多人认为这种做法是不可接受的,因为它破坏了MVC模式.其他人对该方法的可靠性/安全性表示担忧,而我的两部分问题则侧重于后一方面.

  1. Thread.current在整个周期中,散列是否保证可用且对一个且仅一个响应是私有的?

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

谢谢!朱塞佩

Mau*_*res 47

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

  • 测试它们更难,因为在测试使用它的代码时你必须记住设置线程局部变量
  • 使用线程局部变量的类需要知道这些对象对它们不可但在线程局部变量内部这种间接性通常会破坏demeter规律
  • 如果你的框架重用了线程,那么不清理线程本地可能是一个问题(线程局部变量已经启动,并且依赖于|| =调用初始化变量的代码可能会失败

因此,尽管使用它并不是完全没有问题,但最好的方法是不要使用它们,但是有时候你会碰到一个本地线程将成为最简单的解决方案,而不需要改变很多代码和你将不得不妥协,拥有一个不完美的面向对象模型与线程本地或更改相当多的代码来做同样的事情.

所以,这主要是考虑哪种情况对你的情况来说是最好的解决方案,如果你真的走在线程本地路径上,我肯定会建议你用以后要清理的块来做他们完成了,如下所示:

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
Run Code Online (Sandbox Code Playgroud)

这样可确保在使用此线程之前清除线程局部变量.

  • 这就是为什么上面的代码只有一个“ensure”块并且不尝试捕获异常。 (3认同)

Dej*_*mic 21

这个小宝石确保您的线程/请求本地变量不会在请求之间粘贴:https://github.com/steveklabnik/request_store


小智 13

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

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

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


Tom*_*son 5

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

Thread.current如果不是绝对必要,请不要使用线程本地存储

gemrequest_store是另一种解决方案(更好),但只需阅读自述文件即可了解更多远离线程本地存储的原因。

几乎总有更好的方法。

  • 我正在将 Unicorn 与 Rails 多租户应用程序一起使用。你能举一个“更好的方法”的例子吗?您发布的链接引发应用程序错误。谢谢。 (4认同)