【问题标题】:How to set SameSite attribute to 'None; Secure' in Rails3.1.12 and Ruby1.9.3如何将 SameSite 属性设置为“无”; Rails3.1.12 和 Ruby1.9.3 中的 Secure'
【发布时间】:2020-03-30 09:25:56
【问题描述】:

在没有SameSite 属性的情况下设置了与https://example.com/ 的跨站点资源关联的cookie。它已被阻止,因为 Chrome 现在仅在使用 SameSite=NoneSecure 设置时才提供带有跨站点请求的 cookie。您可以在开发人员工具中的 Application>Storage>Cookies 下查看 cookie,并在 https://www.chromestatus.com/feature/5088147346030592https://www.chromestatus.com/feature/5633521622188032 上查看更多详细信息。

请告诉我如何设置 SameSite cookie 属性。提前致谢。

【问题讨论】:

  • 您能否发布更多关于您在 Chrome 控制台中收到此警告的情况的上下文。它是您的代码的一部分还是试图设置 cookie 的某个 3rd 方库?
  • 我们有一套应用程序(超过3个)。所有应用程序都作为 iframe 嵌入到应用程序中,并且能够使用安全令牌进行访问,并且在所有浏览器上都可以正常工作。但是,上述问题出现在“Google Chrome Canary”中,无法访问嵌入式应用程序。为此,我计划添加 SameSite cookie。

标签: ruby-on-rails ruby ruby-on-rails-3.1 ruby-1.9.3 ruby-1.9.2


【解决方案1】:

在 Rails 6.0 和 6.1 中,same_site attribute has been added

cookies["foo"] = {
  value: "bar",
  secure: Rails.application.config.secure_cookies,
  same_site: "None"
}

对于 Rails 5.x 及更低版本,rails_same_site_cookie gem 是将SameSite=None; 添加到所有应用程序 cookie 的不错选择。它使用中间件来做到这一点。

【讨论】:

  • 设置 cookies["foo"] = {value: "bar", same_site: :none, secure: true} 在 Rails 5.2.3 中为我工作,但显然 you need Rack >= 2.1.0
【解决方案2】:

设置自定义标题的方法是将下面的行添加到您的控制器操作中:

response.headers['Set-Cookie'] = 'Secure;SameSite=None'.

【讨论】:

  • 不要SameSite=None添加到您的所有cookies中。这明确将您的 cookie 标记为用于跨站点交付,并且可能不是您想要的。您将失去新默认值提供的 CSRF 保护的安全优势。考虑将SameSite=Lax 添加为您的默认设置,并且在您需要跨站点cookie 时使用SameSite=None。更多信息web.dev/samesite-cookies-explained
【解决方案3】:

Action dispatch cookies负责将cookies写入应用程序中设置的浏览器,这里使用Rack::Utils.set_cookie_header!

rack 1.6版本后增加了对SameSite的支持,你需要在Gemfile中检查你的rack版本,如果是config/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]
        secure = "; secure"  if value[: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

完成后,您可以在创建新 cookie 时设置 SameSite 属性,例如:

cookies['testing'] = {
  value: 'test',
  path: '/',
  expiry: 1.weeks.from_now,
  same_site: :none
}

您也可以将same_site: <value> 添加到您的会话存储中。

希望这会有所帮助!

【讨论】:

  • 我在 rack 1.6.11 实现中没有看到 SameSite=None,所以我相信我们也需要对该版本进行猴子补丁?
  • 是的,如果不支持,我们需要添加补丁。
  • 仅供参考,看起来支持设置 SameSite=None 的最早机架版本是 2.1.0:github.com/rack/rack/commit/…,而在 2.0.0 中支持 LaxSecuregithub.com/rack/rack/commit/…
【解决方案4】:

我所做的如下: 在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

我添加了这个猴子补丁:

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 it always secure, 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

【讨论】:

    【解决方案5】:

    Rails 6.0:

    cookies[:foo] = {
        value: "bar",
        secure: true,
        same_site: :none
    }
    

    您在测试它时必须小心,因为它仅在您运行 HTTPS 时才能在生产/暂存环境中工作。您将无法在开发中对其进行测试。

    【讨论】:

      【解决方案6】:

      此处提供了机架修复的反向移植。

      https://github.com/rack/rack/pull/1547

      它不会发布,因此您可能需要在您的Gemfile 中使用机架叉。

      https://bundler.io/v1.17/guides/git.html

      【讨论】:

        猜你喜欢
        • 2021-01-04
        • 1970-01-01
        • 2020-09-24
        • 2020-02-09
        • 1970-01-01
        • 2018-11-13
        • 1970-01-01
        • 2019-09-27
        • 1970-01-01
        相关资源
        最近更新 更多