开发者

How can I make cookies secure (https-only) by default in rails?

开发者 https://www.devze.com 2023-01-17 00:57 出处:网络
In a Rails controller, I can set a cookie like this: cookies[:foo] = \"bar\" And specify that the \"sec开发者_C百科ure\" (https-only) flag be on like this:

In a Rails controller, I can set a cookie like this:

cookies[:foo] = "bar"

And specify that the "sec开发者_C百科ure" (https-only) flag be on like this:

cookies[:foo, :secure => true] = "bar"

:secure is false by default. How can I have cookies be secure by default, application-wide?

This is on Rails 2.3.8


There's no need to monkeypatch ActionController/ActionDispatch, and force_ssl has side effects (e.g. when behind an ELB).

The most straightforward way to achieve secure cookies is to modify config/initializers/session_store.rb:

MyApp::Application.config.session_store( 
  :cookie_store, 
  key: '_my_app_session',
  secure: Rails.env.production?
)


starting with rails 3.1, according to the rails security guide, you can simply set the following in your application.rb:

config.force_ssl = true

this forces the cookie to be sent over https only (and I assume everything else, too).


Thanks @knx, you sent me down the right path. Here's the monkeypatch I came up with, which seems to be working:

class ActionController::Response
  def set_cookie_with_security(key, value)
    value = { :value => value } if Hash != value.class
    value[:secure] = true
    set_cookie_without_security(key, value)
  end
  alias_method_chain :set_cookie, :security
end

What do you think?


Quick and dirty solution: i think it is possible by modifying []= method in action pack cookies module (actionpack/lib/action_controller/cookies.rb)

from:

    def []=(name, options)
      if options.is_a?(Hash)
        options = options.inject({}) { |options, pair| options[pair.first.to_s] = pair.last; options }
        options["name"] = name.to_s
      else
        options = { "name" => name.to_s, "value" => options }
      end

      set_cookie(options)
    end

to:

    def []=(name, options)
      if options.is_a?(Hash)
        options.merge!({:secure => true})
        options = options.inject({}) { |options, pair| options[pair.first.to_s] = pair.last; options }
        options["name"] = name.to_s
      else
        options = { "name" => name.to_s, "value" => options }
      end

      set_cookie(options)
    end


# session only available over HTTPS
ActionController::Base.session_options[:secure] = true


You should look at the rack-ssl-enforcer gem. I was just looking for a clean answer to this and it solves the problem independent of which version of Rails you're on, plus it's extremely configurable.


You can do this as mentioned in some of the above answers (use secure option in the config/initializers/session_store.rb file):

MyApp::Application.config.session_store :cookie_store, key: '_my_app_session',
                                                       secure: Rails.env.production?

which will only secure the session cookie, but other cookies will not be secure.

If you want to secure all the cookies in your Rails app by default, you can use the secure_headers gem. Just add the secure_headers gem to your Gemfile, bundle install the gem and create a config/initializers/secure_headers.rb file with this content:

SecureHeaders::Configuration.default do |config|
  config.cookies = {
    secure: true, # mark all cookies as "Secure"
  }
end

This will make all the cookies secure in your Rails app by default.

You can also add these recommended configurations and set the httponly and samesite options as well:

SecureHeaders::Configuration.default do |config|
  config.cookies = {
    secure: true, # mark all cookies as "Secure"
    httponly: true, # mark all cookies as "HttpOnly"
    samesite: {
      lax: true # mark all cookies as SameSite=lax
    }
  }
end
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号