根据我的理解,为了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如何使用安全令牌防止重放攻击?


当前回答

另一个答案非常详细,解决了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查询参数…用于记录当前使用情况;它的用途不是 推荐,由于其安全性不足

其他回答

根据我所读到的,它是这样运作的:

问题中概括的大致流程是正确的。在步骤2中,用户X经过身份验证,并授权站点A访问站点B上的用户X的信息。在步骤4中,站点将其Secret传递回站点B,验证自身以及授权码,表明它正在请求什么(用户X的访问令牌)。

总的来说,OAuth 2实际上是一个非常简单的安全模型,加密从未直接发挥作用。相反,Secret和Security Token本质上都是密码,整个事情仅由https连接的安全性保护。

OAuth 2没有针对安全令牌或秘密的重放攻击的保护。相反,它完全依赖于站点B负责这些项目,不让它们流出,并在传输过程中通过https发送(https将保护URL参数)。

授权码步骤的目的只是为了方便,而授权码本身并不是特别敏感。当向站点B请求用户X的访问令牌时,它为站点a的用户X的访问令牌提供了一个公共标识符。仅在站点B上使用用户X的用户id是行不通的,因为可能有许多未完成的访问令牌等待同时分发到不同的站点。

另一个答案非常详细,解决了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查询参数…用于记录当前使用情况;它的用途不是 推荐,由于其安全性不足

老实说,我没有在回答“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安全性最佳当前实践。在那里您还可以找到令牌重放预防部分。

OAuth2本身并不能保护您免受重放攻击。但是,可以使用MTLS或DPoP等“扩展”。你可以在https://marcinjahn.com/technologies/security/oauth2/sender-constraint.html上找到更多信息

这是一块宝石:

https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2

非常简短的总结:

OAuth定义了四个角色:

资源所有者 客户端 资源服务器 授权服务器

您(资源所有者)有一部手机。你有几个不同的电子邮件帐户,但你希望所有的电子邮件帐户都在一个应用程序中,所以你不需要一直切换。因此,您的GMail(客户端)要求访问(通过雅虎的授权服务器)到您的雅虎电子邮件(资源服务器),以便您可以在GMail应用程序上阅读这两封电子邮件。

OAuth存在的原因是GMail存储您的Yahoo用户名和密码是不安全的。