Set “secure” flag on session cookie in RoR even over HTTP

后端 未结 3 2200
没有蜡笔的小新
没有蜡笔的小新 2021-02-20 14:39

In a Rails app, the session cookie can be easily set to include the secure cookie attribute, when sending over HTTPS to ensure that the cookie is not leaked over a

相关标签:
3条回答
  • 2021-02-20 15:28

    The same problem happened to me, and I solved it this way: In session_store.rb I configured:

    MyApp::Application.config.session_store :cache_store, key: COOKIE_NAME, :expire_after => 1.days, :expires_in => 1.days, :domain => 'mydomain.com', same_site: :none
    

    (note that I didn't put the , same_site: :none here, because it would kill the set cookie completely when serving HTTP)

    And then I monkey patched the Rack->Utils->set_cookie_header, by placing this file in the initializers folder

    require 'rack/utils'
    module Rack
      module Utils
        def self.set_cookie_header!(header, key, value)
          case value
          when Hash
            domain  = "; domain="  + value[:domain] if value[:domain]
            path    = "; path="    + value[:path]   if value[:path]
            max_age = "; max-age=" + value[:max_age] if value[:max_age]
            expires = "; expires=" +
                rfc2822(value[:expires].clone.gmtime) if value[:expires]
    
            # Make secure always, even in HTTP
            # secure = "; secure"  if value[:secure]
            secure = "; secure"
    
            httponly = "; HttpOnly" if value[:httponly]
            same_site =
                case value[:same_site]
                when false, nil
                  nil
                when :none, 'None', :None
                  '; SameSite=None'
                when :lax, 'Lax', :Lax
                  '; SameSite=Lax'
                when true, :strict, 'Strict', :Strict
                  '; SameSite=Strict'
                else
                  raise ArgumentError, "Invalid SameSite value: #{value[:same_site].inspect}"
                end
            value = value[:value]
          end
          value = [value] unless Array === value
          cookie = escape(key) + "=" +
              value.map { |v| escape v }.join("&") +
              "#{domain}#{path}#{max_age}#{expires}#{secure}#{httponly}#{same_site}"
    
          case header["Set-Cookie"]
          when nil, ''
            header["Set-Cookie"] = cookie
          when String
            header["Set-Cookie"] = [header["Set-Cookie"], cookie].join("\n")
          when Array
            header["Set-Cookie"] = (header["Set-Cookie"] + [cookie]).join("\n")
          end
    
          nil
        end
      end
    end
    
    0 讨论(0)
  • 2021-02-20 15:39

    The base issue is, that by definition of Set-Cookie, cookies with secure set may only be sent via secure connetions.
    So not sending cookies with secure set over HTTP is the expected behavior.

    You might want to set different cookie options in different environments. In config/environments/developent.rb you clould set

    Rails.application.configure do
      config.session_store :cache_store, key: COOKIE_NAME, same_site: :none
    end
    

    and in production (config/environments/production.rb), where you deploy your site with HTTPS:

    Rails.application.configure do
      config.session_store :cache_store, key: COOKIE_NAME, same_site: :lax, secure: true
    end
    
    0 讨论(0)
  • 2021-02-20 15:42

    Secure cookies are not sent over non-secure connections by definition.

    Terminating SSL upstream is quite common, but you need to pass certain header fields through so that Rails knows and can do the right thing.

    Here's a document that explains the configuration in pretty good detail for nginx. Search for "Set headers" to jump to the section describing the specific headers you need to pass through.

    There are security considerations using this configuration, e.g., if the device terminating SSL is not on the same secure LAN as the Rails host, then you have a vulnerability.

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