根据我的理解,为了Site-A从Site-B访问用户的信息,OAuth 2中发生了以下一系列事件。

Site-A registers on Site-B, and obtains a Secret and an ID. When User tells Site-A to access Site-B, User is sent to Site-B where they tell Site-B that they would indeed like to give Site-A permissions to specific information. Site-B redirects User back to Site-A, along with an Authorization Code. Site-A then passes that Authorization Code along with its Secret back to Site-B in return for a Security Token. Site-A then makes requests to Site-B on behalf of User by bundling the Security Token along with requests.

在高水平上,所有这些在安全和加密方面是如何工作的?OAuth 2如何使用安全令牌防止重放攻击?


当前回答

这里可能是OAuth2如何为所有4种授权类型工作的最简单的解释,即应用程序可以获得访问令牌的4个不同的流。

相似

所有授权类型流都有两部分:

获取访问令牌 使用访问令牌

第二部分“使用访问令牌”对所有流程都是相同的

区别

每个授权类型的流的第一部分“获取访问令牌”各不相同。

然而,一般来说,“获取访问令牌”部分可以概括为5个步骤:

预先注册你的应用(客户端)与OAuth提供商,例如,Twitter等,以获得客户端id/秘密 在你的页面上创建一个带有客户端id和所需范围/权限的社交登录按钮,这样当点击用户时就会被重定向到OAuth提供者进行身份验证 OAuth提供商请求用户授予你的应用(客户端)权限 OAuth提供者发布代码 App(客户端)获取访问令牌

下面是一个并排的图表,比较了基于5个步骤的每个拨款类型流程的不同。

这个图表来自https://blog.oauth.io/introduction-oauth2-flow-diagrams/

每一个都有不同的实现难度、安全性和用例级别。根据您的需要和情况,您将不得不使用其中之一。用哪一种?

客户端凭证:如果你的应用程序只服务于一个用户

资源所有者密码凭据:这应该仅作为最后的手段,因为用户必须将他的凭据移交给应用程序,这意味着应用程序可以做用户所能做的一切

授权代码:获得用户授权的最佳方式

隐式:如果你的应用是移动应用或单页应用

这里有更多关于这个选择的解释:https://blog.oauth.io/choose-oauth2-flow-grant-types-for-app/

其他回答

另一个答案非常详细,解决了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):)中显示

客户端应该使用承载令牌进行身份验证请求 “授权”请求头字段与“承载”HTTP 授权方案。 ... 不应该使用"application/x-www-form-urlencoded"方法 除非在应用程序上下文中,其中参与的浏览器不这样做 可以访问“授权”请求头字段。 ... URI查询参数…用于记录当前使用情况;它的用途不是 推荐,由于其安全性不足

这里可能是OAuth2如何为所有4种授权类型工作的最简单的解释,即应用程序可以获得访问令牌的4个不同的流。

相似

所有授权类型流都有两部分:

获取访问令牌 使用访问令牌

第二部分“使用访问令牌”对所有流程都是相同的

区别

每个授权类型的流的第一部分“获取访问令牌”各不相同。

然而,一般来说,“获取访问令牌”部分可以概括为5个步骤:

预先注册你的应用(客户端)与OAuth提供商,例如,Twitter等,以获得客户端id/秘密 在你的页面上创建一个带有客户端id和所需范围/权限的社交登录按钮,这样当点击用户时就会被重定向到OAuth提供者进行身份验证 OAuth提供商请求用户授予你的应用(客户端)权限 OAuth提供者发布代码 App(客户端)获取访问令牌

下面是一个并排的图表,比较了基于5个步骤的每个拨款类型流程的不同。

这个图表来自https://blog.oauth.io/introduction-oauth2-flow-diagrams/

每一个都有不同的实现难度、安全性和用例级别。根据您的需要和情况,您将不得不使用其中之一。用哪一种?

客户端凭证:如果你的应用程序只服务于一个用户

资源所有者密码凭据:这应该仅作为最后的手段,因为用户必须将他的凭据移交给应用程序,这意味着应用程序可以做用户所能做的一切

授权代码:获得用户授权的最佳方式

隐式:如果你的应用是移动应用或单页应用

这里有更多关于这个选择的解释:https://blog.oauth.io/choose-oauth2-flow-grant-types-for-app/

OAuth 2.0在现实生活中的工作原理:

我开车去上班的路上经过奥拉夫面包店,看到橱窗里最好吃的甜甜圈——我的意思是,那东西滴着巧克力般的美味。所以我走了进去,要求“我必须要那个甜甜圈!”他说:“当然是30美元。”

我知道,30美元一个甜甜圈!一定很好吃!我伸手去拿钱包,突然听到厨师喊道:“不!你没有甜甜圈。”我问:为什么?他说他只接受银行转账。

严重吗?是的,他是认真的。我差点就走开了,但这时甜甜圈对我喊道:“吃了我,我很好吃……”我凭什么违抗甜甜圈的命令?我说好的。

他递给我一张纸条,上面写着他的名字(是厨师,不是甜甜圈):“告诉他们奥拉夫让你来的。”他的名字已经写在纸条上了,所以我不知道这么说有什么意义,不过好吧。

我开了一个半小时的车去银行。我把钞票递给出纳员。我告诉她奥拉夫派我来的。她看了我一眼,好像在说:“我识字。”

她拿着我的纸条,问我要身份证,问我可以给他多少钱。我告诉她30美元。她草草写了几笔,又递给我一张纸条。这个上面有一堆数字,我猜这是他们记录音符的方法。

那时我饿坏了。我冲了出去,一个半小时后我回来了,站在奥拉夫面前,手里拿着我的纸条。他拿了过来,看了看,说:“我会回来的。”

我以为他在买我的甜甜圈,但30分钟后我开始怀疑了。所以我问柜台后面的人“奥拉夫在哪里?”他说"他去拿钱了"“你这是什么意思?”“他把票据送到银行去了。”

嗯……于是奥拉夫拿着银行给我的条子,回到银行去从我的账户里取钱。因为他有银行给我的票据,银行知道他就是我说的那个人,而且因为我和银行谈过,他们知道只给他30美元。

我一定花了很长时间才弄明白,因为当我抬起头来的时候,奥拉夫终于站在我面前,把我的甜甜圈递给了我。在我离开之前,我不得不问:“奥拉夫,你总是这样卖甜甜圈吗?”“不,我以前做的不一样。”

嗯。当我走回我的车时,我的电话响了。我没去接,可能是我的工作让我开除的,我的老板真是个***。此外,我一直在想我刚刚经历的过程。

我的意思是,想想看:我可以让奥拉夫从我的银行账户中取出30美元,而不必把我的账户信息告诉他。我也不用担心他会取太多的钱,因为我已经告诉银行他只能取30美元。银行知道他是合适的人因为他有他们让我交给奥拉夫的纸条。

好吧,我宁愿从口袋里掏出30美元给他。但现在他有了那张钞票,我可以告诉银行让他每周拿30美元,然后我就可以去面包店了,再也不用去银行了。如果我愿意,我甚至可以通过电话订购甜甜圈。

我当然不会那么做,那个甜甜圈太恶心了。

我想知道这种方法是否有更广泛的应用。他提到这是他的第二种方法,我可以称之为Olaf 2.0。总之我得回家了,我得开始找新工作了。但在我从镇另一头的新店里买到草莓奶昔之前,我需要一些东西来洗掉甜甜圈的味道。

老实说,我没有在回答“OAuth 2如何使用安全令牌防止重放攻击?”这个问题的答案中找到一个,这是一个主要的问题。

首先,OP描述的访问方案只适用于OAuth 2.0 -授权码授予提供的一个流。还有其他的流动。所有流的一个共同特征是,作为成功身份验证的结果,客户端会收到一个访问令牌。

如何保护自己免受重放攻击?这是可能的(有一些保留意见),但您需要理解,首先,这需要一组措施(如下所述),其次,您不能100%地保护自己免受这种类型的攻击,有时您可以立即阻止未经授权的访问尝试,有时您只能在发生此类攻击时缩短持续时间。

所以你需要做什么:

Use signed JWT as your tokens. Use a very short expiration time for access tokens, 10 minutes is enough in my opinion. Your authorization server must issue refresh tokens, which is generally optional according to the standard. The expiration time of refresh tokens should not be too long, for each situation it should be solved differently, for example, for a website, I would set it a little longer than a normal user session. You can also implement session expiration when the user is idle, but this applies to the application logic and is not provided for by the standard (this is a fairly simple mechanism, but it's out of the scope of the question). You must store issued refresh tokens in the authorization server database. However, you don't have to store access token data to take advantage of self-contained JWTs. It is advisable to store data about refresh tokens during the lifetime of the session, that is, until the time when the refresh token expires (in fact, it will not be one token, but a family - more on that below). Take general measures to protect against token/session theft, they are probably well-known, among them are the following: use only a secure connection; if you store tokens on the end user side using cookies, set cookie flags to protect them, more details here; implement protection against cross-site request forgery (CSRF), more details here. (Now the most interesting part begins) Implement refresh token rotation. This means that every time a client uses a refresh token to get a new access token (because the access token has expired), a new refresh token must be issued along with the new access token, and the old refresh token must be invalidated. It could just be a flag in the database indicating that the refresh token is invalid. Each time the authorization server issues a refresh token, it must add to it (among other required/recommended) the following claims: jti with a unique token id and a private claim with any unassigned public name, e.g. fid with unique token family id (within one session). For example, refresh token 1 had jti 3c30a712-247b-4091-b692-8c3e92b83bb2, fid 4eb44450-84e9-4fbc-830e-33935e20f7e6, after issuing refresh token 2 instead of refresh token 1, it might have a new jti f467cf40-8cd7-485e-8711-b5c657832fc6 but will have the same fid 4eb44450-84e9-4fbc-830e-33935e20f7e6. You keep holding the entire refresh token family in the database until the last one, the one that is still valid, becomes invalid, for example, until it expires. *You can do without the fid claim, then you will have to link the entire chain / family of refresh tokens issued within the same session using relational database mechanisms. Implement an absolute expiration time for refresh tokens. Each time, when the authorization server within the same session issues a new refresh token instead of the previous refresh token, the value of its exp claim should not exceed the expiration time of the very first refresh token. For example, if refresh token 1 had a value of 1643384057 for exp claim, then each subsequent refresh token, for example refresh token 5, should also contain the same value 1643384057 in the exp claim. Implement refresh token replay (reuse) detection. Perhaps you have already guessed what to do next. Each time the authorization server receives a request to issue an access token, the authorization server, among other things, must check whether the presented refresh token is one from an existing chain / family and is not marked invalid. If an authorization server receives an invalidated refresh token that is in a family that has a valid (latest) refresh token, it MUST invalidate the most recent refresh token (no valid tokens left) and MUST refuse to issue an access token.

当攻击者窃取令牌/会话并试图重用它时会发生什么。有以下几种情况:

The token/session was used by the attacker before, at the request of a legitimate user, the client requested the issuance of new access and refresh tokens. That is, the attacker managed to do it first. Then, at the next request of a legitimate user, the client will send an invalid refresh token to the authorization server (because the attacker made the request earlier and the legitimate user's refresh token was invalidated). The session will be invalidated. The token/session was used by a legitimate user, and the stolen token/session was later used by an attacker. In this case, the same thing will happen - the session will be invalidated, I think this is understandable. It is possible that after the token/session was stolen, the legitimate user did not send any more requests, then the attacker will have access until the absolute expiration of the refresh token (see point 9).

授权服务器无法知道谁是合法用户,谁是攻击者,因此在这种情况下,最后一个(有效的)刷新令牌总是无效的,从而使会话过期/无效。在此之后,合法用户可以通过输入密码来验证自己的身份,而攻击者则不能。

了解这是如何工作的,您应该选择与令牌过期相关的值,这些值与您的项目相关。

我建议您深入研究相关标准,以及OAuth 2.0安全性最佳当前实践。在那里您还可以找到令牌重放预防部分。

这就是Oauth 2.0的工作原理,本文对此进行了详细解释