仅使用SameSite Lax Cookie进行SSO的可行性? 原始SSO流程需要SameSite=None结论

如何解决仅使用SameSite Lax Cookie进行SSO的可行性? 原始SSO流程需要SameSite=None结论

背景

我现在正在为我的cookie实现SameSite。我已经有HttpOnlySecure,所以我认为这可能没什么大碍。

为什么会崩溃

好吧,事实证明,一旦实施该设置,很多东西就会坏掉。 SameSite=LaxSameSite=Strict都发生了这种情况。我进行了一些研究,发现这是由于SSO容易因SameSite设置为LaxStrict(而不是None)而损坏:

我的主浏览器(Iron 70)基于Chromium 70,因此我从未遇到过2月份向Chrome 80用户推出的更改,该更改默认是将没有SameSite值的Cookie设置为Lax 。我安装了最新的Google Chrome浏览器便携式设备以进行检查,有趣的是,该功能目前不是(很可惜)默认为SameSite=Lax,因为它可能曾经使用过-我的网站才在那里中断了一旦我明确启用以下标头:

Header edit Set-Cookie ^(.*)$ $1;SameSite=Lax

这似乎是因为在没有显式SameSite的情况下,Chromium默认将其视为"LAX + POST w/ 2-minute rule"(我正在快速测试,所以它在2分钟内)。

即使使用Lax,我所有的单点登录都已中断,并且我的实时聊天不再起作用-使用Websockets或XHR请求。当我尝试进行单点登录时,我最终还是退出了主要网站,这也没有多大意义-基本上,一切都搞砸了。

  1. 是否有希望使XHR或Websockets与Lax一起使用?我在chat.example.com上聊天,但也可以在sub.someotherdomain.org上的侧面板中访问它。我的猜测是,这里的答案是,解决该问题的唯一方法是使URL在同一域中可用,而Apache只是在幕后指向同一脚本。烦人,但这可以完成-但是还有另一种方法吗?

  2. 我的更大问题是:单点登录与LaxStrict本质上不兼容吗?我在这方面还没有发现太多。所有文章似乎都认为用Lax来破坏SSO是不可避免的,甚至有一些图表解释了为什么会破坏,但是SSO是否必须那样?

主流解决方法

大多数站点都说要SameSite=None来解决此问题,并在所有用户代理中强制执行旧的行为。从技术上讲,这行得通,但我想知道是否有希望使用Lax替代方法?如何在不屈服于SameSite=None的情况下使其工作?

解决方法

TL; DR-是的,您可以使用SameSite=Lax(但不能使用SameSite=Strict)并且不会破坏SSO!

关于SameSite cookie,有两点要注意:

  • 宽松禁止使用POST
  • 进行跨域请求
  • 严格还禁止使用GET的跨域请求

有用的摘要: enter image description here

来源:https://www.wst.space/cookies-samesite-secure-httponly/

严格根本不起作用,因为它阻止了任何形式的跨源请求发送cookie,这使得SSO完全不可能。 Strict甚至不是可行的候选人。

这给我们留下了LaxNone(到目前为止是默认值,并逐渐被Lax取代)。

  1. 是否有希望让XHR或Websocket重新与Lax一起使用?我在chat.example.com聊天,但我也允许访问 在sub.someotherdomain.org上的侧面板中显示。我的猜测是 答案是,解决该问题的唯一方法是 Apache仅指向同一域上可用的URL 相同的脚本在幕后。烦人,但可以完成-但是 还有另一种方法吗?

这里最好的解决方案是在幕后重写URL,因此您无需维护重复的资源。使用Apache的mod_rewrite重写URL或简单地执行include('path/to/file.php')都是一个简单的解决方案。返回的 内容将完全相同-但如果它需要发送Lax cookie,则浏览器必须将其发送到当前域的祖先域。

  1. 我更大的问题是:单点登录本质上与LaxStrict不兼容吗?

不,幸运的是,不!

我并没有发现太多 这个。所有文章似乎都将使用Lax来破坏SSO视为 不可避免,甚至有一些图解释了为什么 休息,但SSO是否必须那样?

是真的,很多SSO页面SameSite=Lax中断-但这不是 不可避免-特定于实现。让我们比较一下原始方法和与SameSite=Lax cookie兼容的修订方法。

原始SSO流程(需要SameSite=None

  1. 用户导航到sub.example.org-当前未登录,因为此站点上未设置cookie
  2. 页面检测到未登录,并自动重定向到example.com上用于SSO的页面-如果未在此进行身份验证,它将重定向回并给出用户名/密码提示。如果用户已通过验证,请继续。
  3. example.com上,读取用户的会话数据并为SSO调用创建唯一的令牌。将令牌转储到数据库中,并使用插入的令牌将其发布回原始站点。
  4. 回到sub.example.org,读取已发布的令牌并在数据库中查询该令牌,然后从中检索用户ID。
  5. sub.example.org上的本地会话中设置用户ID-由于$_SESSION['mysession']example.comsub.example.org上返回相同的信息,因此该会话可以按预期工作(因为用户ID永远不会更改,从技术上讲,它们是重复的Cookie)。

这将以SameSite=Lax 断开。为什么?因为发给身份验证者的原始请求使用的是POST请求-这是对外部域的请求-SameSite=Lax SameSite=Strict都认为这很危险-并且跨域POST不会将Cookie发送到目标。因此,Cookie不可用,并且验证者不知道要验证的用户,因此它不能为该用户创建临时令牌,然后再发回。这就是为什么这不起作用。

但是,这里要注意的重要一点是POST请求 没有发送任何敏感数据 (至少在上述实现中) 。只是询问进行身份验证-它甚至没有任何敏感数据要发送!

那么,为什么我们首先POST?回想一下SameSite=Lax允许第一级GET导航(SameSite=Strict不允许)。因此,我们可以简单地使用GET而不是POST来进行初始重定向

解决方法

如何在不屈服于 SameSite=None

这是怎么回事。由于Lax允许使用最高级别的GET,但不允许使用POST(这可能是“危险的”),因此请使用GET进行初始重定向,而不要使用POST。

矛盾的是,GET的安全性可能不及POST,但是敏感数据(用户令牌)仅在最终重定向上发送回请求身份验证的站点-初始重定向仅表示“嘿,我正在请求验证”。

这里的a brief excerpt支持这种可能性,得出的结论是:

最后,IdP 应继续以在其Cookie起作用 浏览器默认将其设置为SameSite = Lax(当前在 Chrome 78-81和Firefox 72设置了相同的站点默认标志)。 通常,只有当JSESSIONID出现时,IdP本身才会中断 设置为SameSite'Strict'(严格),除了什么时候 明确尝试使用旧版Safari设置SameSite = None 在MacOS https://bugs.webkit.org/show_bug.cgi?id=198181)。但是关于 要实现单点登录,您可能会发现运行质量下降,并且 发生以下可能性:

初始重定向需要在授权域上使用cookie,而请求授权的域不是在请求cookie-它是根据POST对其设置 cookie。因此,从理论上讲,这应该与Lax一起使用,因为在最终的POST请求(仅初始请求)上不需要cookie。最终的POST重定向将无法根据该请求发送Cookie……但这不需要-我们将在{{1} }本身,并根据此设置cookie。天才!

修订后的SSO流程

原始SSO -需要POST

  1. 请求者SameSite=None到身份验证提供者
  2. 身份验证提供程序接收cookie(需要POST或未定义的None)并创建临时令牌
  3. 身份验证提供程序使用令牌重定向回请求者,令牌对其进行验证并创建会话cookie

修订后的SSO -与SameSite兼容:

  1. 请求者SameSite=Lax到身份验证提供者
  2. 身份验证提供程序接收cookie(因为现在是GET,而不是GET)并创建临时令牌
  3. 身份验证提供程序使用令牌重定向回请求者,令牌对其进行验证并创建会话cookie

一个区别-就是这样-初始重定向上为POST,而不是GET。这是可行的,因为初始重定向不包含任何敏感信息。这个POST很可能是POST。通过将其设置为一个,我们可以提高整个会话cookie以及所有“记住我” cookie的安全级别-不错!

我已经在Chromium 70和Chrome 84中对此进行了测试,并带有严格的标志和阻止了第三方Cookie的功能(因此没有“ Lax + POST”,只是“ Lax”)。这确实有效。您还可以将任何“记住我” cookie设置为GET-如果由于没有正在进行的会话,验证者需要使用它们自发地创建会话,则只要存在重定向,就可以使用这样做的cookie。 SameSite=Lax而不是GET-我们很好!

结论

SSO 可以与POST一起使用。显然,XHR,动态CSS,websocket等将不会,但是可以将它们简单地代入原始域之后。通过在初始重定向上使用Lax而不是GET,您可以转到使用POST使用cookie。

更复杂的SSO流程可能有所不同-我在这里给出的只是一个非常简单的SSO示例。但是,SSO和SameSite=Lax互不兼容-您可以通过稍微调整SSO设置使其工作,如果您需要进行其他更改,则不会中断。

请注意,您仍然仍可以与SameSite=Lax进行会话-如果您的整个站点都在一个主机名上并且非常敏感,我建议您改为使用。但是,如果需要执行SSO,则至少可以使用SameSite=Strict(当然不能使用SameSite=Lax)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 <select id="xxx"> SELECT di.id, di.name, di.work_type, di.updated... <where> <if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 <property name="dynamic.classpath" value="tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -> systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping("/hires") public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate<String
使用vite构建项目报错 C:\Users\ychen\work>npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-