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