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

后端 未结 8 1880
不知归路
不知归路 2021-02-01 14:34

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

cookies[:foo] = \"bar\"

And specify that the \"secure\" (https-only) flag be on like this:

相关标签:
8条回答
  • 2021-02-01 15:00

    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).

    0 讨论(0)
  • 2021-02-01 15:02

    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?
    )
    
    0 讨论(0)
  • 2021-02-01 15:04

    To force SSL and enable the secure cookie for an entire Ruby on Rails application, enable force_ssl in your environment file such as production.rb.

    # config/environments/production.rb
    config.force_ssl = true
    

    If you need to support HTTP and HTTPS traffic with your Ruby on Rails application, set the secure cookie flag for your application so that session cookies are ONLY sent over HTTPS.

    The consequence is you can no longer maintain session state over HTTP, but you at least protect yourself from session hijacking attacks.

    # config/initializers/session_store.rb
    # set secure: true, optionally only do this for certain Rails environments (e.g., Staging / Production
    Rails.application.config.session_store :cookie_store, key: '_testapp_session', secure: true
    

    Here is the video tutorial of same.

    0 讨论(0)
  • 2021-02-01 15:19

    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
    
    0 讨论(0)
  • 2021-02-01 15:19

    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 讨论(0)
  • 2021-02-01 15:21

    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?

    0 讨论(0)
提交回复
热议问题