在RoR中的会话cookie上设置“安全”标志,甚至通过HTTP

时间:2013-01-24 09:51:43

标签: ruby-on-rails security session-cookies

在Rails应用程序中,通过HTTPS发送时,可以轻松地将会话cookie设置为包含secure cookie属性,以确保cookie不会通过非HTTP连接泄露。

但是,如果Rails应用程序不使用HTTPS,而只使用HTTP,则它似乎根本不设置cookie。
虽然这确实有意义,但在这种情况下,还有一个单独的前端负载均衡器,它负责终止SSL连接。从LB到Rails应用程序,连接只是HTTP。

即使不使用HTTPS,如何强制Rails应用设置secure Cookie?

3 个答案:

答案 0 :(得分:8)

根据定义,不通过非安全连接发送安全cookie。

终止SSL上游是很常见的,但是你需要传递某些头字段,以便Rails知道并且可以做正确的事情。

Here's a document以非常详细的方式解释了nginx的配置。搜索“设置标题”以跳转到描述您需要通过的特定标题的部分。

使用此配置有一些安全注意事项,例如,如果终止SSL的设备与Rails主机不在同一个安全LAN上,那么您就有漏洞。

答案 1 :(得分:0)

我遇到了同样的问题,我通过以下方式解决了这个问题: 在session_store.rb中,我配置了:

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

(请注意,我没有在此处放置, same_site: :none,因为在提供HTTP服务时它将完全杀死set cookie)

然后我通过将文件放置在initializers文件夹中,以猴子方式对Rack-> Utils-> set_cookie_header进行了修补

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

答案 2 :(得分:0)

基本问题是,根据Set-Cookie的定义,带有安全集的cookie只能通过安全连接来发送。
因此,不希望通过HTTP发送带有安全设置的cookie。

您可能想在不同的环境中设置不同的cookie选项。 在config / environments / developent.rb文件中,您应该设置

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

以及在生产环境(config / environments / production.rb)中,使用HTTPS部署站点:

Rails.application.configure do
  config.session_store :cache_store, key: COOKIE_NAME, same_site: :lax, secure: true
end