質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
Cookie

HTTPにおけるCookieとは、クライアントのウェブブラウザ上に保存された一時的なデータを指します。クライアント側のJavaScriptでも、サーバー側のHTTPヘッダーでもクッキーの読み書き・修正・削除が可能です。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Q&A

解決済

3回答

2085閲覧

rails のcookies設定において、SameSiteの値の変更したい

Lampii

総合スコア19

Cookie

HTTPにおけるCookieとは、クライアントのウェブブラウザ上に保存された一時的なデータを指します。クライアント側のJavaScriptでも、サーバー側のHTTPヘッダーでもクッキーの読み書き・修正・削除が可能です。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

1グッド

0クリップ

投稿2019/09/03 11:56

簡単にできそうなのですが、なかなか良い方法がなく。。質問させていただきます。

▼ゴールは、下記のように devtoolで SameSiteの値に「None」が入っていることです。 ※図はJavaScriptで実装しました
イメージ説明

▼apidockのcookieのページをみても、 httponlysecureはあるのに、samesiteはありません…。
https://apidock.com/rails/ActionDispatch/Cookies

session_storeはredisを使っていて、cookiesは別の値を管理しています。
以下、試してみたことです。

1. cookiesのリファレンスにはないが、かき加えてみた

▼元の記述

cookies.permanent[:key] = value

▼書き換えてみた

cookies.permanent[:key] = { value: value, samesite: 'none' }

反映されませんでした。

2.secureheader(gem)を使ってみた

https://morizyun.github.io/ruby/library-secureheaders.html

入れてみましたが、cookiesにはSameSiteは反映されず、またgemインストール直後から他で予期せぬ設定変更が起きてしまい、外しました。
(丁寧に設定をオーバーライドしていけば正常に動くかもしれませんが、影響範囲が大きく確認の工数が上がりそうなので諦めました)

直接cookie文字列の書き換えができたらと思うのですが…
何か良い方法ご存知の方がいらっしゃいましたら、ご教示いただけますと幸いです。

ちなみにこの変更の目的は、chromeのcookieがデフォルトでSameSite=Laxになるらしいというものの対策になります。(プロダクトがWebにiframeで埋め込むタイプのものになるので、必要なものかと)
https://www.chromestatus.com/feature/5088147346030592

何卒、よろしくお願いいたします。

unhappychoice👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

最終的に、プルリクがあがっている修正部分を、initializers/にmonkey patchを置いて、オーバーライドする形で実装しました。
今回は、SameSite=Noneであればよいので直接かいています。

正式アップデートがあれば、アップデート対応したいと思います。
わりと裏技的実装だと思うのですが、まずい点等あれば教えてもらえたら嬉しいです。。

▼対象コミット
rails/actionpack/lib/action_dispatch/middleware/cookies.rb
https://github.com/rails/rails/commit/e3e79fc0e167a00749731708991b650e3828e8d2#diff-69714203ccef60fcead8d4eff741a883
rack/utils.rb
https://github.com/rack/rack/commit/c859bbf7b53cb59df1837612a8c330dfb4147392#diff-7c1a24d5b2fe58a6f925c7cacc6c55e7

initializers/cookie_samesite_patch.rb

Ruby

1 2module ActionDispatch 3 class Cookies 4 class CookieJar #:nodoc: 5 def handle_options(options) # :nodoc: 6 if options[:expires].respond_to?(:from_now) 7 options[:expires] = options[:expires].from_now 8 end 9 10 options[:path] ||= "/" 11 12 options[:same_site] = 'None' 13 14 if options[:domain] == :all || options[:domain] == "all" 15 # If there is a provided tld length then we use it otherwise default domain regexp. 16 domain_regexp = options[:tld_length] ? /([^.]+.?){#{options[:tld_length]}}$/ : DOMAIN_REGEXP 17 18 # If host is not ip and matches domain regexp. 19 # (ip confirms to domain regexp so we explicitly check for ip) 20 options[:domain] = if (request.host !~ /^[\d.]+$/) && (request.host =~ domain_regexp) 21 ".#{$&}" 22 end 23 elsif options[:domain].is_a? Array 24 # If host matches one of the supplied domains without a dot in front of it. 25 options[:domain] = options[:domain].find { |domain| request.host.include? domain.sub(/^./, "") } 26 end 27 end 28 end 29 end 30end 31 32module Rack 33 module Utils 34 def add_cookie_to_header(header, key, value) 35 case value 36 when Hash 37 domain = "; domain=#{value[:domain]}" if value[:domain] 38 path = "; path=#{value[:path]}" if value[:path] 39 max_age = "; max-age=#{value[:max_age]}" if value[:max_age] 40 # There is an RFC mess in the area of date formatting for Cookies. Not 41 # only are there contradicting RFCs and examples within RFC text, but 42 # there are also numerous conflicting names of fields and partially 43 # cross-applicable specifications. 44 # 45 # These are best described in RFC 2616 3.3.1. This RFC text also 46 # specifies that RFC 822 as updated by RFC 1123 is preferred. That is a 47 # fixed length format with space-date delimited fields. 48 # 49 # See also RFC 1123 section 5.2.14. 50 # 51 # RFC 6265 also specifies "sane-cookie-date" as RFC 1123 date, defined 52 # in RFC 2616 3.3.1. RFC 6265 also gives examples that clearly denote 53 # the space delimited format. These formats are compliant with RFC 2822. 54 # 55 # For reference, all involved RFCs are: 56 # RFC 822 57 # RFC 1123 58 # RFC 2109 59 # RFC 2616 60 # RFC 2822 61 # RFC 2965 62 # RFC 6265 63 expires = "; expires=" + 64 rfc2822(value[:expires].clone.gmtime) if value[:expires] 65 secure = "; secure" if value[:secure] 66 httponly = "; HttpOnly" if (value.key?(:httponly) ? value[:httponly] : value[:http_only]) 67 same_site = 68 case value[:same_site] 69 when false, nil 70 nil 71 when :none, 'None', :None 72 '; SameSite=None' 73 when :lax, 'Lax', :Lax 74 '; SameSite=Lax'.freeze 75 when true, :strict, 'Strict', :Strict 76 '; SameSite=Strict'.freeze 77 else 78 raise ArgumentError, "Invalid SameSite value: #{value[:same_site].inspect}" 79 end 80 value = value[:value] 81 end 82 value = [value] unless Array === value 83 84 cookie = "#{escape(key)}=#{value.map { |v| escape v }.join('&')}#{domain}" \ 85 "#{path}#{max_age}#{expires}#{secure}#{httponly}#{same_site}" 86 87 case header 88 when nil, '' 89 cookie 90 when String 91 [header, cookie].join("\n") 92 when Array 93 (header + [cookie]).join("\n") 94 else 95 raise ArgumentError, "Unrecognized cookie header value. Expected String, Array, or nil, got #{header.inspect}" 96 end 97 end 98 module_function :add_cookie_to_header 99 end 100end 101 102

投稿2019/09/09 05:26

Lampii

総合スコア19

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

Rails 本体に関してはまさに PR が開かれているようです。
rails/rails #28297

そのためRails デフォルトの方法ではまだ不可能ということになりますので、 Rack middleware なりを用意して Rack レベルでセットする必要がありそうです。

参考 How do I set a cookie with a (ruby) rack middleware component?

投稿2019/09/04 01:12

編集2019/09/04 01:13
unhappychoice

総合スコア1531

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Lampii

2019/09/04 02:22

早速ありがとうございます!!なるほど、、まさに対応中なんですね。 変なことを言っていたら恐縮なんですが、middlewareの設定を入れるということは、アプリケーションサーバーにRackではなくunicornを採用していた場合、unicornの設定になるでしょうか…? nginx+unicornの構成です。 それともunicornを使っていても、Rackは噛んでいると思ってよかったでしょうか?(無知ですみません。。)
unhappychoice

2019/09/04 02:51 編集

Rack middleware は玉ねぎ状の構造をしていて、一番外で受け取ったリクエストを内側に渡していって、一番内側が rails で書いているコードの部分になっています。 すでにいくつもの Rack middleware が使われていて、 `rails middleware` で確認できるかと思います。 cookie に追記するような玉ねぎの皮を一枚自前で追加するだけなので、詳しいやり方は `Rails Rack middleware` 等で調べればすぐに出るかと思います。
Lampii

2019/09/04 02:44

イメージとてもつきやすいです!ありがとうございます! `rails middleware` やってみました!ActionDispatchも、すでに実装されているmiddlewareの一部なんですね。。理解がはかどります。 このあたり理解が浅いので、学びながら追加してみようと思います。ありがとうございます!!
guest

0

※自己解決方法にかいたつもりでしたが回答してました。。削除がすぐにできなかったので、重複しますがこちらにもかいておきます。

最終的に、プルリクがあがっている修正部分を、initializers/にmonkey patchを置いて、オーバーライドする形で実装しました。
今回は、SameSite=Noneであればよいので直接かいています。

正式アップデートがあれば、アップデート対応したいと思います。
わりと裏技的実装だと思うのですが、まずい点等あれば教えてもらえたら嬉しいです。。

▼対象コミット
rails/actionpack/lib/action_dispatch/middleware/cookies.rb
https://github.com/rails/rails/commit/e3e79fc0e167a00749731708991b650e3828e8d2#diff-69714203ccef60fcead8d4eff741a883
rack/utils.rb
https://github.com/rack/rack/commit/c859bbf7b53cb59df1837612a8c330dfb4147392#diff-7c1a24d5b2fe58a6f925c7cacc6c55e7

initializers/cookie_samesite_patch.rb

Ruby

1 2module ActionDispatch 3 class Cookies 4 class CookieJar #:nodoc: 5 def handle_options(options) # :nodoc: 6 if options[:expires].respond_to?(:from_now) 7 options[:expires] = options[:expires].from_now 8 end 9 10 options[:path] ||= "/" 11 12 options[:same_site] = 'None' 13 14 if options[:domain] == :all || options[:domain] == "all" 15 # If there is a provided tld length then we use it otherwise default domain regexp. 16 domain_regexp = options[:tld_length] ? /([^.]+.?){#{options[:tld_length]}}$/ : DOMAIN_REGEXP 17 18 # If host is not ip and matches domain regexp. 19 # (ip confirms to domain regexp so we explicitly check for ip) 20 options[:domain] = if (request.host !~ /^[\d.]+$/) && (request.host =~ domain_regexp) 21 ".#{$&}" 22 end 23 elsif options[:domain].is_a? Array 24 # If host matches one of the supplied domains without a dot in front of it. 25 options[:domain] = options[:domain].find { |domain| request.host.include? domain.sub(/^./, "") } 26 end 27 end 28 end 29 end 30end 31 32module Rack 33 module Utils 34 def add_cookie_to_header(header, key, value) 35 case value 36 when Hash 37 domain = "; domain=#{value[:domain]}" if value[:domain] 38 path = "; path=#{value[:path]}" if value[:path] 39 max_age = "; max-age=#{value[:max_age]}" if value[:max_age] 40 # There is an RFC mess in the area of date formatting for Cookies. Not 41 # only are there contradicting RFCs and examples within RFC text, but 42 # there are also numerous conflicting names of fields and partially 43 # cross-applicable specifications. 44 # 45 # These are best described in RFC 2616 3.3.1. This RFC text also 46 # specifies that RFC 822 as updated by RFC 1123 is preferred. That is a 47 # fixed length format with space-date delimited fields. 48 # 49 # See also RFC 1123 section 5.2.14. 50 # 51 # RFC 6265 also specifies "sane-cookie-date" as RFC 1123 date, defined 52 # in RFC 2616 3.3.1. RFC 6265 also gives examples that clearly denote 53 # the space delimited format. These formats are compliant with RFC 2822. 54 # 55 # For reference, all involved RFCs are: 56 # RFC 822 57 # RFC 1123 58 # RFC 2109 59 # RFC 2616 60 # RFC 2822 61 # RFC 2965 62 # RFC 6265 63 expires = "; expires=" + 64 rfc2822(value[:expires].clone.gmtime) if value[:expires] 65 secure = "; secure" if value[:secure] 66 httponly = "; HttpOnly" if (value.key?(:httponly) ? value[:httponly] : value[:http_only]) 67 same_site = 68 case value[:same_site] 69 when false, nil 70 nil 71 when :none, 'None', :None 72 '; SameSite=None' 73 when :lax, 'Lax', :Lax 74 '; SameSite=Lax'.freeze 75 when true, :strict, 'Strict', :Strict 76 '; SameSite=Strict'.freeze 77 else 78 raise ArgumentError, "Invalid SameSite value: #{value[:same_site].inspect}" 79 end 80 value = value[:value] 81 end 82 value = [value] unless Array === value 83 84 cookie = "#{escape(key)}=#{value.map { |v| escape v }.join('&')}#{domain}" \ 85 "#{path}#{max_age}#{expires}#{secure}#{httponly}#{same_site}" 86 87 case header 88 when nil, '' 89 cookie 90 when String 91 [header, cookie].join("\n") 92 when Array 93 (header + [cookie]).join("\n") 94 else 95 raise ArgumentError, "Unrecognized cookie header value. Expected String, Array, or nil, got #{header.inspect}" 96 end 97 end 98 module_function :add_cookie_to_header 99 end 100end 101 102

投稿2019/09/09 05:29

Lampii

総合スコア19

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問