据我了解,为了让 Site-A
从 Site-B
访问 用户 信息,OAuth 2 中发生了以下事件链。
Site-A 在 Site-B 上注册,并获得一个 Secret 和一个 ID。当用户告诉站点 A 访问站点 B 时,用户将被发送到站点 B,在那里他们告诉站点 B 他们确实希望授予站点 A 对特定信息的权限。站点 B 将用户重定向回站点 A,并附有授权代码。然后,站点 A 将该授权代码连同其秘密一起传递回站点 B,以换取安全令牌。然后,站点 A 通过将安全令牌与请求捆绑在一起,代表用户向站点 B 发出请求。
所有这些在安全和加密方面是如何工作的? OAuth 2 如何使用安全令牌防止诸如重放攻击之类的事情?
code
),但 OAuth 2.0 中定义了与不同用例相关的其他授权类型(例如非用户相关的授权类型) )。
OAuth 2.0 在现实生活中的工作原理:
当我在上班的路上开车经过奥拉夫的面包店时,我看到橱窗里有最美味的甜甜圈——我的意思是,那东西正滴着巧克力味。所以我进去并要求“我必须有那个甜甜圈!”。他说“当然是30美元。”
是的,我知道,一个甜甜圈30美元!一定很好吃!当我突然听到厨师大喊“不!不要给你甜甜圈”时,我伸手去拿我的钱包。我问:为什么?他说他只接受银行转账。
严重地?是的,他是认真的。我差点就走开了,但随后甜甜圈对我喊道:“吃我,我很好吃……”。我有什么资格违抗甜甜圈的命令?我说了可以。
他递给我一张纸条,上面写着他的名字(厨师,而不是甜甜圈):“告诉他们奥拉夫派你来的”。他的名字已经写在纸条上,所以我不知道这样说有什么意义,但是好吧。
我开车一个半小时到我的银行。我把纸条递给出纳员;我告诉她奥拉夫派我来的。她给了我一个这样的眼神,那种说,“我可以阅读”。
她拿了我的纸条,要了我的身份证,问我可以给他多少钱。我告诉她30美元。她潦草地写了几句,又递给我一张纸条。这个上面有一堆数字,我猜这就是他们记录笔记的方式。
那个时候我饿死了。我冲出那里,一个半小时后我又回来了,站在奥拉夫面前,我的纸条被拉长了。他接过它,看了看,说:“我会回来的。”
我以为他在拿我的甜甜圈,但 30 分钟后我开始怀疑。所以我问柜台后面的人“奥拉夫在哪里?”。他说“他去拿钱”。 “你是什么意思?”。 “他记笔记到银行”。
嗯……所以奥拉夫拿着银行给我的纸条,回到银行从我的账户里取钱。因为他有银行给我的票据,银行知道他就是我说的那个人,因为我和银行谈过,他们知道只给他 30 美元。
我肯定花了很长时间才弄清楚这一点,因为当我抬起头来时,奥拉夫终于站在我面前把我的甜甜圈递给了我。在我离开之前,我不得不问,“奥拉夫,你总是这样卖甜甜圈吗?”。 “不,我以前做的不一样。”
嗯。当我走回我的车时,我的电话响了。我懒得回答,可能是我的工作要求解雇我,我的老板就是这样的***。此外,我还在思考我刚刚经历的过程。
我的意思是想一想:我能够让奥拉夫从我的银行账户中取出 30 美元,而无需向他提供我的账户信息。而且我不必担心他会拿走太多钱,因为我已经告诉银行他只允许拿 30 美元。银行知道他是合适的人选,因为他有他们给我要给奥拉夫的纸条。
好吧,当然我宁愿从口袋里掏出 30 美元给他。但是现在他有了那张纸条,我可以告诉银行让他每周拿 30 美元,然后我可以直接出现在面包店,我不必再去银行了。如果我愿意,我什至可以通过电话订购甜甜圈。
我当然不会那样做——那个甜甜圈真恶心。
我想知道这种方法是否有更广泛的应用。他提到这是他的第二种方法,我可以称之为 Olaf 2.0。不管怎样,我还是回家吧,我得开始找新工作了。但在我从镇上的那个新地方买一份草莓奶昔之前,我需要一些东西来洗去那个甜甜圈的味道。
根据我所阅读的内容,这就是它的工作原理:
问题中概述的一般流程是正确的。在第 2 步中,用户 X 已通过身份验证,并且还授权站点 A 访问用户 X 在站点 B 上的信息。在第 4 步中,站点将其 Secret 传递回站点 B,对自身进行身份验证,以及授权代码,指示什么它要求(用户 X 的访问令牌)。
总体而言,OAuth 2 实际上是一个非常简单的安全模型,加密永远不会直接发挥作用。相反,Secret 和 Security Token 本质上都是密码,整个事情只有通过 https 连接的安全性来保护。
OAuth 2 没有针对 Security Token 或 Secret 的重放攻击的保护。相反,它完全依赖于站点 B 对这些项目负责并且不让它们离开,并且依赖于它们在传输过程中通过 https 发送(https 将保护 URL 参数)。
授权码步骤的目的只是为了方便,授权码本身并不是特别敏感。当向站点 B 询问用户 X 的访问令牌时,它为站点 A 的用户 X 的访问令牌提供了一个通用标识符。仅站点 B 上的用户 X 的用户 ID 不会起作用,因为可能有许多未完成的访问令牌等待同时分发给不同的站点。
OAuth 是一种协议,3 方应用程序可以使用该协议访问您存储在另一个网站中的数据,而无需您的帐户和密码。有关更正式的定义,请参阅 Wiki 或规范。
这是一个用例演示:
我登录 LinkedIn 并想联系我的 Gmail 联系人中的一些朋友。 LinkedIn 支持这一点。它将从 gmail 请求安全资源(我的 gmail 联系人列表)。所以我点击这个按钮:一个网页弹出,它显示 Gmail 登录页面,当我输入我的帐户和密码时:Gmail 然后显示一个同意页面,我点击“接受”:现在 LinkedIn 可以访问我在 Gmail 中的联系人:
下面是上面例子的流程图:
https://i.stack.imgur.com/bt7k0.png
第 1 步:LinkedIn 从 Gmail 的授权服务器请求令牌。
第 2 步:Gmail 授权服务器对资源所有者进行身份验证并向用户显示同意页面。 (如果用户尚未登录,则需要登录 Gmail)
第 3 步:用户授予 LinkedIn 访问 Gmail 数据的请求。
第 4 步:Gmail 授权服务器返回访问令牌。
第 5 步:LinkedIn 使用此访问令牌调用 Gmail API。
第 6 步:如果访问令牌有效,Gmail 资源服务器会返回您的联系人。 (令牌将由 Gmail 资源服务器验证)
您可以从有关 OAuth here 的详细信息中获得更多信息。
图 1,取自 RFC6750:
+--------+ +---------------+
| |--(A)- Authorization Request ->| Resource |
| | | Owner |
| |<-(B)-- Authorization Grant ---| |
| | +---------------+
| |
| | +---------------+
| |--(C)-- Authorization Grant -->| Authorization |
| Client | | Server |
| |<-(D)----- Access Token -------| |
| | +---------------+
| |
| | +---------------+
| |--(E)----- Access Token ------>| Resource |
| | | Server |
| |<-(F)--- Protected Resource ---| |
+--------+ +---------------+
这就是 Oauth 2.0 的工作原理,在 this article 中有很好的解释
https://i.stack.imgur.com/Mo2wi.jpg
这是一个宝石:
https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2
非常简短的总结:
OAuth 定义了四个角色:
资源所有者客户端资源服务器授权服务器
您(资源所有者)有一部手机。您有多个不同的电子邮件帐户,但您希望所有电子邮件帐户都在一个应用程序中,因此您无需不断切换。因此,您的 GMail(客户端)请求访问(通过 Yahoo 的授权服务器)您的 Yahoo 电子邮件(资源服务器),以便您可以在 GMail 应用程序上阅读这两封电子邮件。
OAuth 存在的原因是因为 GMail 存储您的 Yahoo 用户名和密码是不安全的。
https://i.stack.imgur.com/6CMie.png
另一个答案非常详细,解决了 OP 提出的大部分问题。
详细说明,特别是为了解决 OP 的问题“OAuth 2 如何使用安全令牌防止重放攻击?”,在实施 OAuth 2 的官方建议中有两个额外的保护:
代币的有效期通常很短(https://www.rfc-editor.org/rfc/rfc6819#section-5.1.5.3):
令牌的较短到期时间是一种防止以下威胁的方法:重放...
当站点 A 使用令牌时,建议它不会作为 URL 参数显示,而是在授权请求标头字段中显示 (https://www.rfc-editor.org/rfc/rfc6750):
客户端应该使用带有“Bearer”HTTP 授权方案的“Authorization”请求标头字段使用不记名令牌发出经过身份验证的请求。 ...“application/x-www-form-urlencoded”方法不应该被使用,除非在参与的浏览器无权访问“授权”请求头字段的应用程序上下文中。 ... URI 查询参数... 用于记录当前使用情况;不推荐使用它,因为它存在安全缺陷
这可能是关于 OAuth2 如何适用于所有 4 种授权类型的最简单解释,即应用程序可以获取访问令牌的 4 种不同流程。
相似
所有授权类型的流程都有 2 个部分:
获取访问令牌
使用访问令牌
第二部分“使用访问令牌”对于所有流都是相同的
区别
每种授权类型的“获取访问令牌”流程的第一部分各不相同。
但是,一般来说,“获取访问令牌”部分可以概括为 5 个步骤:
使用 OAuth 提供程序(例如 Twitter 等)预先注册您的应用程序(客户端)以获取客户端 ID/秘密 在您的页面上创建一个带有客户端 ID 和所需范围/权限的社交登录按钮,以便在单击时将用户重定向到 OAuth 提供程序以经过身份验证 OAuth 提供者请求用户向您的应用(客户端)授予权限 OAuth 提供者发出代码 应用(客户端)获取访问令牌
这是一个并排图表,比较了基于 5 个步骤的每种授权类型流程的不同之处。
此图来自 https://blog.oauth.io/introduction-oauth2-flow-diagrams/
https://i.stack.imgur.com/kC8bX.png
每个都有不同级别的实施难度、安全性和用例。根据您的需要和情况,您将不得不使用其中之一。使用哪个?
客户端凭据:如果您的应用只为单个用户提供服务
资源所有者密码凭据:这只能作为最后的手段,因为用户必须将他的凭据交给应用程序,这意味着应用程序可以做用户可以做的所有事情
授权码:获得用户授权的最佳方式
隐式:如果您的应用是移动应用或单页应用
这里有更多关于选择的解释:https://blog.oauth.io/choose-oauth2-flow-grant-types-for-app/
老实说,在回答“OAuth 2 如何使用安全令牌防止重放攻击之类的事情?”的答案中,我没有找到一个答案,这是主要的问题。
首先,OP 描述的访问方案仅适用于 OAuth 2.0 - Authorization Code Grant 提供的流程之一。还有其他流量。所有流程的共同特征之一是,作为成功认证的结果,客户端会收到一个访问令牌。
如何保护自己免受重放攻击?这是可能的(有一些保留),但您需要了解,首先,这需要一套措施(如下所述),其次,您不能仅 100% 保护自己免受此类攻击,有时您可以立即阻止未经授权的访问尝试,有时您只能在发生此类攻击时缩短其持续时间。
那么你需要什么:
使用签名的 JWT 作为您的令牌。对访问令牌使用非常短的到期时间,我认为 10 分钟就足够了。您的授权服务器必须发出刷新令牌,根据标准,这通常是可选的。刷新令牌的过期时间不宜过长,对于每种情况应该以不同的方式解决,例如,对于一个网站,我会将它设置为比普通用户会话长一点。您还可以在用户空闲时实现会话过期,但这适用于应用程序逻辑并且标准未提供(这是一种相当简单的机制,但超出了问题的范围)。您必须将发布的刷新令牌存储在授权服务器数据库中。但是,您不必存储访问令牌数据即可利用自包含 JWT。建议在会话的生命周期内存储有关刷新令牌的数据,即直到刷新令牌过期(实际上,它不会是一个令牌,而是一个系列 - 更多内容如下)。采取一般措施来防止令牌/会话盗窃,它们可能是众所周知的,其中包括:仅使用安全连接;如果您使用 cookie 在最终用户端存储令牌,请设置 cookie 标志以保护它们,更多详细信息请点击此处;实施针对跨站点请求伪造 (CSRF) 的保护,更多详细信息请点击此处。 (现在最有趣的部分开始了)实现刷新令牌轮换。这意味着每次客户端使用刷新令牌获取新的访问令牌时(因为访问令牌已过期),新的刷新令牌必须与新的访问令牌一起发出,并且旧的刷新令牌必须失效。它可能只是数据库中的一个标志,表明刷新令牌无效。每次授权服务器发布刷新令牌时,它必须向其中添加(以及其他必需/推荐的)以下声明:具有唯一令牌 ID 的 jti 和具有任何未分配公共名称的私有声明,例如具有唯一令牌系列 ID 的 fid (一次会议内)。例如,刷新令牌 1 具有 jti 3c30a712-247b-4091-b692-8c3e92b83bb2,fid 4eb44450-84e9-4fbc-830e-33935e20f7e6,在发出刷新令牌 2 而不是刷新令牌 1 之后,它可能具有新的 jti f467cf40-8cd7- 485e-8711-b5c657832fc6 但将具有相同的 fid 4eb44450-84e9-4fbc-830e-33935e20f7e6。您一直在数据库中保留整个刷新令牌系列,直到最后一个(仍然有效的)变为无效,例如,直到它过期。 *您可以不使用 fid 声明,然后您必须使用关系数据库机制链接在同一会话中发布的整个刷新令牌链/系列。为刷新令牌实现绝对过期时间。每次,当同一会话中的授权服务器发出新的刷新令牌而不是先前的刷新令牌时,其 exp 声明的值不应超过第一个刷新令牌的到期时间。例如,如果刷新令牌 1 的 exp 声明值为 1643384057,则每个后续刷新令牌(例如刷新令牌 5)在 exp 声明中也应包含相同的值 1643384057。实施刷新令牌重放(重用)检测。也许您已经猜到下一步该做什么了。每次授权服务器接收到发布访问令牌的请求时,授权服务器必须检查所提供的刷新令牌是否来自现有链/家族并且未被标记为无效。如果授权服务器接收到无效的刷新令牌,该令牌属于具有有效(最新)刷新令牌的系列,则它必须使最近的刷新令牌无效(没有剩余有效令牌)并且必须拒绝发出访问令牌。
当攻击者窃取令牌/会话并尝试重用它时会发生什么。有几种情况:
攻击者之前使用了令牌/会话,应合法用户的请求,客户端请求发布新的访问和刷新令牌。也就是说,攻击者首先设法做到了。然后,在合法用户的下一次请求时,客户端将向授权服务器发送一个无效的刷新令牌(因为攻击者较早地提出了请求,并且合法用户的刷新令牌已失效)。会话将失效。令牌/会话被合法用户使用,被盗的令牌/会话后来被攻击者使用。在这种情况下,同样的事情也会发生——会话会失效,我认为这是可以理解的。有可能在令牌/会话被盗后,合法用户没有再发送任何请求,那么攻击者将可以访问,直到刷新令牌绝对到期(见第 9 点)。
授权服务器无法知道谁是合法用户,谁是攻击者,因此在这种情况下,最后一个(有效的)刷新令牌总是无效的,从而使会话过期/无效。之后,合法用户可以通过输入密码来验证自己的身份,而攻击者则不能。
了解其工作原理后,您应该选择与您的项目相关的令牌到期相关的值。
我建议您更深入地了解 related standards 以及 OAuth 2.0 Security Best Current Practice。您还会在此处找到 Token Replay Prevention section。
OAuth2 本身并不能保护您免受重放攻击。但是,可以使用 MTLS 或 DPoP 等“扩展”。您可以在 https://marcinjahn.com/technologies/security/oauth2/sender-constraint.html 了解更多信息
不定期副业成功案例分享