默认情况下,如何在 Rails 中使 cookie 安全(仅限 https)?

Posted

技术标签:

【中文标题】默认情况下,如何在 Rails 中使 cookie 安全(仅限 https)?【英文标题】:How can I make cookies secure (https-only) by default in rails? 【发布时间】:2011-04-15 23:23:13 【问题描述】:

在 Rails 控制器中,我可以这样设置 cookie:

cookies[:foo] = "bar"

并指定“安全”(仅限 https)标志如下:

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

:secure 默认为假。如何让 cookie 在应用程序范围内默认安全?

这是在 Rails 2.3.8 上

【问题讨论】:

【参考方案1】:

ActionController/ActionDispatch 无需猴子补丁,force_ssl 有副作用(例如当behind an ELB 时)。

实现安全cookie最直接的方法是修改config/initializers/session_store.rb

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

【讨论】:

这是正确的答案(已验证这在 Rails 4.2.7.1 中有效)。为了方便测试,设置secure: true,然后您可以验证cookie是否正确生成。然后可以改回Rails.env.production? 看起来这只会影响会话cookie。询问者要求将安全作为所有 cookie 的默认设置。 @david-cain 能否验证该解决方案是否适用于所有 cookie?【参考方案2】:

您可以按照上述某些答案中的说明执行此操作(使用config/initializers/session_store.rb 文件中的secure 选项):

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

这只会保护会话 cookie,但其他 cookie 将不安全。

如果您想默认保护 Rails 应用程序中的所有 cookie,您可以使用 secure_headers gem。只需将 secure_headers gem 添加到您的 Gemfile 中,bundle install gem 并使用以下内容创建一个 config/initializers/secure_headers.rb 文件:

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

默认情况下,这将使 Rails 应用中的所有 cookie 安全。

您还可以添加这些推荐配置并设置httponlysamesite 选项:

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

【讨论】:

【参考方案3】:

强制 SSL 并为整个 Ruby on Rails 启用安全 cookie 应用程序,在您的环境文件中启用 force_ssl,例如 生产.rb。

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

如果您需要使用 Ruby on Rails 支持 HTTP 和 HTTPS 流量 应用程序,为您的应用程序设置安全 cookie 标志,以便 会话 cookie 仅通过 HTTPS 发送。

结果是您无法再通过 HTTP 维护会话状态,但您至少可以保护自己免受会话劫持攻击。

# 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是same的视频教程。

【讨论】:

【参考方案4】:

您应该查看 rack-ssl-enforcer gem。我只是在寻找一个干净的答案,它解决了与您使用的 Rails 版本无关的问题,而且它非常可配置。

【讨论】:

secure_cookies gem。【参考方案5】:
# session only available over HTTPS
ActionController::Base.session_options[:secure] = true

【讨论】:

这是 rails 4 的新功能吗? 我不知道。但是,在 Rails 4 中它可以工作。您也可以在您的 Rails 版本中检查此属性。 这仅用于会话 cookie,对吗?一般不用于 cookie? 它在 Rails 4.1 中不起作用:undefined method 'session_options' for ActionController::Base:Class (NoMethodError) 这个放在哪里?【参考方案6】:

从 rails 3.1 开始,根据the rails security guide,您可以在application.rb 中简单地设置以下内容:

config.force_ssl = true

这会强制 cookie 仅通过 https 发送(我也假设其他所有内容)。

【讨论】:

起初这让我很困惑:config.force_ssl主要 目的是只允许 rails 应用程序通过 SSL 工作,但它在 cookie 上启用 secure 标志。在设置此配置之前,请确保您对它的其余效果没问题:***.com/questions/15676596/…【参考方案7】:

感谢@knx,你让我走上了正确的道路。这是我想出的猴子补丁,它似乎正在工作:

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

你怎么看?

【讨论】:

John,我们在 Rails 应用程序中的哪个位置放置了上面的类? 太棒了。谢谢。还有一件事,我的开发环境 - 使用 webrick - 当我在 environment.rb 中将安全标志设置为 true 时,我无法通过我的登录屏幕 - 我注意到响应中有来自应用程序的设置 cookie。知道会发生什么吗? 如果您在 cookie 上将安全标志设置为 true,则不会为非 https 请求发送 cookie。您在开发环境中使用 https 吗? 我确实在我的 cookie 上将安全标志设置为 true(通过 ActionController::Base.session)。我用 ssl 设置了 apache httpd,它在我的开发环境中转发到 WebRick 并且仍然得到相同的行为 对于在 Rails 3.2.x 上尝试此功能的任何人,我相信 set_cookie 已被重构为 ActionDispatch::Response 所以猴子补丁应该可以工作。【参考方案8】:

快速而肮脏的解决方案:我认为可以通过修改动作包 cookie 模块 (actionpack/lib/action_controller/cookies.rb) 中的 []= 方法来实现

来自:

    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

到:

    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

【讨论】:

以上是关于默认情况下,如何在 Rails 中使 cookie 安全(仅限 https)?的主要内容,如果未能解决你的问题,请参考以下文章

Rails 5 和设计:如何在不更改默认策略的情况下禁用基于令牌的策略上的会话

在 Rails 中使 TimeWithZone 对象变得惰性

如何在Rails中使数据库字段为只读?

如何在 Ruby on Rails 迁移中使列唯一并为其编制索引?

如何在 ruby​​ on rails 中使每个 user_id 的列数据唯一

如何在 C# 中使图像可见