逃げる8回で会心の一撃

Web エンジニアのサトウリョウスケが開発とか色々書くブログです

駆け込みで Chrome 80 の SameSite=None; Secure の対応をやった🍪

ご存知の方も多いかと思いますが、 Chrome 80 から 3rd Party Cookie の取り扱いが厳しくなり、特に指定がないと外部サイトの CookiePOST・iframe・XHR 等のリクエス で送られなくなります。

developers-jp.googleblog.com

2 月の Chrome 80 以降、SameSite 値が宣言されていない Cookie は SameSite=Lax として扱われます。外部アクセスは、SameSite=None; Secure 設定のある Cookie のみ可能になります。ただし、これらが安全な接続からアクセスされることが条件です。

とはいえ完全に無効になるわけではなく、 SameSite という属性が宣言されていない CookieLax という区分がデフォルトで適用されるという物なので、サーバーから返す Cookie に対して明示的に SameSiteNone に指定して、かつ Secure という属性を付与すれば、従来どおり Cookie が送信されます。

去年の秋くらいにもこの Cookie の対応が必要かどうか、会社で調査していたんですが、その時点では影響を受ける箇所が無くて、特に何も対応せずにスルーしていたんですが、現在開発してる新機能がたまたまこの影響を受ける機能だったため、急遽対応することになりました。

結構厳しいな、と思ったのは、これが原因で動かないことに気付くのが結構難しいんですよね。 シングルサインオンみたいな機能を作ってるとドメインが異なるので 3rd Party Cookie の扱いになります。 そして Cookie に入っているはずの Session ID が送られてこないので、サーバー側で Session が見つからずにエラー。

自分の手元の Chrome は 79 で、まだ上記の制限が入っていなかったんですが、以前影響範囲を調査した時に chrome://flags から有効にするフラグを ON にしていたので、他のエンジニアの環境では動作するけど、自分だけ動かないということになり、もしかして、と思って気付いた感じです。

リリース後に気付いてたらヤバかったですね。。

で、こういう問題は Rails みたいなフレームワークで対応してくれよって気持ちになるんですが、ちゃんと対応する PR は作られていて、すでに merge もされています。

github.com

ですが、 2020/2/20 現在、これを反映した Rails はまだリリースされていないみたいですね。(最新が 2019/12/19 にリリースされた 6.0.2.1 ) また、 Rails 5.2 に反映されるかどうかは微妙な感じになっています。

https://github.com/rails/rails/pull/28297#issuecomment-577414543

We will backport to 6.0 as a bug fix, but I don't know this warrants a backport to a security only release like 5.2. Rails 6.0 was released 6 months ago, and upgrading applications could be high, high priority if that problem is so important.

バグ修正として6.0にバックポートしますが、これが5.2のようなセキュリティのみのリリースへのバックポートを保証するかどうかわかりません。 Rails 6.0は6か月前にリリースされました。その問題が非常に重要な場合、アプリケーションのアップグレードは優先度が高くなる可能性があります。

自分の開発環境は恥ずかしながら Rails 4.2 (今年中にアップデートします!)なので、当然反映されるはずもないので、自前で Rack を作成して対応しました。 参考まで以下のようなコードになります。

# config/initializers/custom_rack_middleware.rb

# NOTE: Rails 6.0.x であれば以下の処理は不要となる。
Rails.application.config.middleware.insert_before(
  ActionDispatch::Cookies,
  CustomRackMiddleware::SetSameSiteOptionOnCookie
)
# lib/custom_rack_middleware/set_same_site_option_on_cookie.rb

# TODO: Rails 6.0.x にアップデートしたら削除する
module CustomRackMiddleware
  class SetSameSiteOptionOnCookie
    def initialize(app)
      @app = app
    end

    def call(env)
      status, headers, body = @app.call(env)

      cookies = headers['Set-Cookie']
      if cookies.present?
        processed_cookies = cookies.split("\n").map do |cookie|
          "#{cookie}; SameSite=None; Secure"
        end
        headers['Set-Cookie'] = processed_cookies.join("\n")
      end

      [status, headers, body]
    end
  end
end

2020/02/22 追記

ローカルの開発環境など HTTP リクエストをする環境だと、 SameSite=None の設定を入れると Cookie が送られなくなるようです。

ローカルでは上述の Rack を読み込ませないようにするなどの工夫が必要だと思います。