在iFrame中加载Rails应用程序的会话不起作用



我有一个Rails 6.1应用程序,它使用会话来存储一些数据。当我在iFrame中打开应用程序时,会话不起作用(当导航到应用程序的另一个页面时,我无法获得它们的值,仍然在相同的iFrame中)

我读了很多关于这个的文章,并摆弄了cookiesame_site配置等。

我也读到Chrome是原因,但我在Safari中尝试了同样的问题。

但是我不想在rails应用程序和包含iFrame的页面之间共享会话。我只是想让应用程序在iFrame内正常工作。

你知道是什么原因吗?

为了让你的会话cookie在iframe中工作,你需要显式地将它的SameSite设置为None

Rails版本≥6.1

Rails 6.1引入了一个新的配置选项,您可以在config/application.rb中设置它:

config.action_dispatch.cookies_same_site_protection = :none

指南的相关部分在这里。

Rails版本<6.1

最好的方法是使用rails_same_site_cookie gem。

Secure设置

当将SameSite设置为None时,您还必须确保将Secure设置为true时发送cookie。当您取消config/environments/production.rb中的以下行注释时,就会发生这种情况:

config.force_ssl = true

这个变化是从哪里来的?

Rails 6.1的相关提交在这里。这归结为Rails现在显式地为它发送的每个cookie设置SameSite=Lax

测试

我发现本地测试设置的最佳方法是运行一个单独的服务器(例如Middleman实例)来模拟将Rails应用程序嵌入iframe中的第三方页面。

然后您可以将一个浏览器选项卡指向localhost:3000/my/iframed/page,另一个指向lvh.me:4567/my/embedding/page。您应该能够登录一个选项卡,并在另一个选项卡中充当已登录的用户。

在类似生产的环境中进行测试也是至关重要的。

NonevsLaxvsStrict

如果你要设置SameSite=Lax,这个设置只会在两个选项卡都指向相同的域时起作用,例如localhost。对于SameSite=Strict,它根本不起作用。

当你在测试时,如果你从例如:lax切换回:none,你将从两个选项卡注销。

响应头

注意,更改SameSite的值不足以设置您的Rails应用程序在iframe中工作。您还需要在相关的控制器动作中设置正确的标头,如下所示:

response.set_header("X-Frame-Options", "ALLOW-FROM #{embedding_url}")
response.set_header("Content-Security-Policy", "frame-ancestors 'self' #{embedding_url}")

embedding_url可以是*,如果你想让任何人都能够通过iframe嵌入你的Rails应用程序。

为了进一步阅读,makandra的好心人专门编制了一张关于SameSite设置的卡片。

Safari浏览器支持在safari中,除了要求用户取消在他们的首选项中选中防止跨站点跟踪复选框外,没有什么可以解决这个问题。在未来,同样可能适用于所有主要的浏览器(见这里的相关Chrome博客文章)。