ruby - Unintentional Session Hijacking in Rails 4.2.4 (Devise / Warden), Phusion Passenger 5.0.24 -
background details
we encountered problem wherein user unintentionally hijack session of user b trying access controller-generated download @ (nearly) same time user a.
we still not 100% of of conditions necessary happen, can reliably reproduce problem in our production , staging environments. important details of environments follows.
environment details
application server: phusion passenger 5.0.21 or 5.0.24 (meaning tried both versions , both reproduced issue)
framework: rails 4.2.4
language: ruby 2.2.3
operating system: centos 6
interestingly, can not reproduce problem using phusion passenger 4.0.53.
steps reproduce hijacking
it may seem simple possibly true, necessary.
- user logs system
- user b logs system
- user , b both rapidly click same download button @ (nearly) same time
that's takes someone's session unintentionally hijacked. (it seems roulette whether or b's session hijacked, although isn't random seems.)
we know user's session has been hijacked because can see current session's user first , last name displayed on page.
each time, 1 user "becomes" other user.
if user access roles different, means can potentially have different level of access. instance, might become admin if that's session unintentionally hijacked ....
code required
it seemed phusion passenger thing causing problem because when switched version 4, issue no longer appeared.
after code changes though, determined method in our controller code seemed contribute problem happening.
here's sample controller method generate problem on phusion passenger 5.0.21 or 5.0.24:
def sample_method respond_to |format| format.csv { headers.merge!({'cache-control'=>'must-revalidate, post-check=0, pre-check=0'}) render :text => proc { |response, output| 100.times |i| output.write("this line #{i}\n") end } } end end
it seems our modification of cache-control may have played issue.
perhaps shouldn't have modified this, we're hoping might have insights how cache-control parameter have power plunge different session.
in order test this, must have route maps controller#sample_method , must have button available click download file.
i realize specifying want csv , aren't returning csv, replaced our actual csv proc in case because our csv generated in separate class.
the above code in environment listed above reproduce issue.
other dependencies
we using devise gem user authentication. if setup test application try reproduce problem, you'd need devise , 2 accounts setup.
incidentally, you'll need 2 people on 2 separate computers test out. you'll both need logged system @ same time , try click button bunch of times @ same time well.
i realize problem seems far-fetched, did manifest in our environment. takes specific versions of phusion passenger, specific set of headers, , render block in order happen, happen does. (the specific code listed in code required section.)
the fix
the news there way around issue code. able use #send_data method inside our format.csv block.
instead of other block of code, doing along these lines:
format.csv { send_data data_here, filename: filename, type: 'text/csv', disposition: 'attachment' }
this cleaner code , better code. still worried there kind of larger issue - either in passenger or perhaps in our code itself.
ideas?
maybe expert in community can explain how unintentional session hijacking possible.
it seems perhaps session cookies not being sent , forth properly. (we not using database our sessions.)
although have fix particular instance of problem, weren't sure if there may other underlying problems (perhaps in passenger?) allow problem manifest in first place.
it seems strange issue.
on other hand, perhaps it's doing our headers bad idea.
your insights appreciated!
your cache-control statement allows caching (it forces revalidation, ie browser/cache won't serve request straight cache doesn't stop cached response being returned), whereas default cache control headers rails emit contain 'private' not allow caching intermediary proxies (browser caching still allowed).
given response may include rails session cookie, caching response , reusing user results in second user acquiring cookie first user. if using database backed session store, you'd still cookie identifying row in database use. time displaying private content need careful caching headers.
the reason passenger version relevant passenger 5 includes http caching layer. bug still there in passenger 4, harder trigger (for example 2 users behind corporate proxy).
you should marking response private, meaning intermediary caches (including 1 in passenger) won't cache response. phusion wrote blog post describing in more detail. can turn off turbocaching entirely - given default rails marks responses private may not doing useful in app anyway.
Comments
Post a Comment