甚至通过 HTTP 在 RoR 中的会话 cookie 上设置“安全”标志
Posted
技术标签:
【中文标题】甚至通过 HTTP 在 RoR 中的会话 cookie 上设置“安全”标志【英文标题】:Set "secure" flag on session cookie in RoR even over HTTP 【发布时间】:2013-01-08 00:43:34 【问题描述】:在 Rails 应用程序中,会话 cookie 可以轻松设置为包含 secure
cookie 属性,当通过 HTTPS 发送时,以确保 cookie 不会通过非 HTTP 连接泄漏。
但是,如果 Rails 应用程序不使用 HTTPS,而仅使用 HTTP,那么它似乎根本没有设置 cookie。 虽然这确实有些道理,但在这种情况下,有一个单独的前端负载平衡器,负责终止 SSL 连接。从 LB 到 Rails 应用程序的连接仅是 HTTP。
如何强制 Rails 应用设置 secure
cookie,即使不使用 HTTPS?
【问题讨论】:
我理解正确,如果我通过cookies[:somekey] = value: 'somevalue', secure: true
设置cookie,那么Rails over HTTP 的响应中没有设置cookie?
@SebastianGoodman 好问题 - 但还没有实际测试过,我说的是自动会话 cookie,所以它实际上并没有在代码中明确设置。如果可行的话,也许这可能是一种解决方法...
所以当你说“会话 cookie 可以很容易地设置为包含安全 cookie 属性”时,你在代码中的表现如何?
这里有同样的问题。当我们想通过 http 发送它们时,Rails 中的某些东西会阻止安全 cookie(因为我们稍后会有 https 转换器)
【参考方案1】:
根据定义,安全 cookie 不会通过非安全连接发送。
终止 SSL 上游很常见,但您需要传递某些标头字段,以便 Rails 知道并可以做正确的事情。
Here's a document 非常详细地解释了 nginx 的配置。搜索“设置标题”以跳转到描述您需要通过的特定标题的部分。
使用此配置存在安全考虑,例如,如果终止 SSL 的设备与 Rails 主机不在同一个安全 LAN 上,那么您就有漏洞。
【讨论】:
非常好,这就是我希望找到的。有趣的是,这是 nginx 的解决方案,而不是 Rails 的解决方案......谢谢! 感谢您的链接 - 将proxy_set_header X-Forwarded-Proto https;
添加到 nginx 配置效果很好!
我们仍然需要一个解决方案,如何强制 Rails 不阻止安全 http cookie
不可能不阻止安全-http cookie,因为根据“安全”的定义,这些 cookie 不能通过 http(仅 https)发送,这基本上就是“安全”的意思。【参考方案2】:
同样的问题也发生在我身上,我是这样解决的: 在 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时完全杀死设置的cookie)
然后我修改了 Rack->Utils->set_cookie_header,将此文件放在 initializers
文件夹中
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
【讨论】:
【参考方案3】:基本问题是,根据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
【讨论】:
以上是关于甚至通过 HTTP 在 RoR 中的会话 cookie 上设置“安全”标志的主要内容,如果未能解决你的问题,请参考以下文章