Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rack::Session::Redis#generate_unique_sid's unique session key generation logic does not work #69

Open
hogelog opened this issue May 26, 2022 · 4 comments
Assignees

Comments

@hogelog
Copy link
Contributor

hogelog commented May 26, 2022

Rack::Session::Redis#generate_unique_sid is a method that generates new unique session key that it does not conflict with an existing session key.

But it seems does not work well after #37 PR.

Reproduction

I checked with the following code, which is prone to session key collisions.

require "bundler/inline"

gemfile do
  source "https://rubygems.org"
  gem "sinatra", "2.2.0"
  gem "webrick", "1.7.0"
  gem "redis-rack", "2.1.4"
end

require "sinatra"
require "redis-rack"

# Returns a counted-up value for each invocation since the process was started
class Countup
  def self.hex(len)
    @count ||= 0
    @count += 1
    sprintf("%0#{len}d", @count)
  end
end

enable :sessions
set :sessions, secure_random: Countup
set :session_store, Rack::Session::Redis

get "/" do
  session[:access] ||= 0
  session[:access] += 1
  "sid: #{session.id}, access: #{session[:access]}"
end

Sinatra::Application.run!

Procedure

  • Launch above application with ruby app.rb
  • Access by browser (sid: 00000000000000000000000000000001)
    • session[:access] increases with each access.
  • Kill ruby app.rb application and relaunch.
  • Access by secret browser (sid: 00000000000000000000000000000001)
    • session[:access] is initialized.
    • session is shared with first browser and secret browser.

The above situation occurs even with correct random number generation logic, although the collisions are fewer.

How to fix

Revert #37 is easy way, maybe.
If you want to avoid that, it would require a more complicated modification.

@tubbo
Copy link
Contributor

tubbo commented Oct 15, 2022

@hogelog Given one uses the default SecureRandom.hex, and doesn't circumvent the logic for actually generating a random value, how often could a session ID collision happen?

@hogelog
Copy link
Contributor Author

hogelog commented Oct 29, 2022

@hogelog Given one uses the default SecureRandom.hex, and doesn't circumvent the logic for actually generating a random value, how often could a session ID collision happen?

Unfortunately, I don't know exactly how often ID collisions happen, as I noticed it while looking at the code.

In default, sid (= public session id) is SecureRandom.hex(32) when secure: true.
And private session id value is "2::#{Digest::SHA256.hexdigest(sid)}".
https://github.com/rack/rack-session/blob/9cc829041ba82c9c1313fdf6ca5ce446621dfd88/lib/rack/session/abstract/id.rb#L248-L250

(Assuming that SecureRandom generates perfectly uniformly)
So public session id collision rate is 1 - ((2^256 - 1)/2^256)^N. If session count is 10,000,000, rate is 1 - ((2^256 - 1)/2^256)^10,000,000 ≈ 8.6 × 10^-71.
https://www.wolframalpha.com/input?i=1+-+%28%282%5E256-1%29%2F2%5E256%29%5E10000000
Ref: https://en.wikipedia.org/wiki/Birthday_problem

SHA256 is hash function digesting to 256 bits. If SHA256 is a perfect hash function without bias, then a 256-bit input would be hashed to a 256-bit value without collision.

Ofcource there are no perfect random generator and hash function algorightms, real collision rate would be more often. But, in any case, collision rate would be not so high.

@hogelog
Copy link
Contributor Author

hogelog commented Oct 29, 2022

On the other hand, the code at https://github.com/redis-store/redis-rack/blob/v2.1.4/lib/rack/session/redis.rb#L23 does not seem to be working properly at the moment. I am thinking of sending a fix along with tests.

@tubbo
Copy link
Contributor

tubbo commented Feb 22, 2023

@hogelog i just merged your changes to redis-store, wondering if that helps any with this issue?

@tubbo tubbo self-assigned this Feb 22, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants