user938363
user938363

Reputation: 10350

How safe is the thread local in Rails?

In our multi tenant Rails 4.2 app, we would like to define a thread local current_token for User model and intend to use it through out the whole app. Here is the how the current_token is defined:

class User < ActiveRecord::Base
  def self.current_token=(token)
    Thread.current['current_token'] = token
  end

  def self.current_token
    Thread.current['current_token']
  end
end

The token is retrieved with User.current_token. It is vital to keep User.current_token thread safe and alive throughout the lifespan of a user session. It is pointed out that the thread local may be cleared up by some web server such as puma. We would like to get feedback from the community about how sound is the thread local in real production. What kind of problem we should be aware of (and possible solution if there is one).

Upvotes: 3

Views: 1505

Answers (2)

spickermann
spickermann

Reputation: 106882

Thread.current per se is secure. The risk of Thread.current is that you have to use it correctly, because it doesn't reset automatically at the end of a request. Some examples:

  • Imagine you set a token in Thread.current in one request and do not set to an other token in the next (perhaps because there was no token in the next request), then the old token will still be available.

  • Or you plan to nullify Thread.current at the end of each request to ensure each request starts with a blank Thread.current. Will happen if a request fails with an exception, does it still get nullified?

It is just error-prone to work with Thread.current directly and there is the risk of exposing data from one request (one user) to a later request (user) on the same server.

You might want to check the RequestStore gem that internally uses Thread.current, but warps it with some layers of security.

Upvotes: 6

Paul A Jungwirth
Paul A Jungwirth

Reputation: 24551

I've never heard of an issue with puma and thread locals. You might want to use the sentient_user gem since its behavior is very close to what you're describing. The only difference is that instead of keeping around a token, you keep around the whole user.

I will note that this pattern is basically a global variable, so it acts like an unstated parameter to any method that uses it. But it can be nice for auditing, so that it is always available no matter where you need it.

Upvotes: 1

Related Questions