[英]JWT refresh token. Can it be self contained?
我想保留这样的令牌(有效载荷):
访问令牌
{
"user": "john_doe",
"iat": 1444262543,
"exp": 1444262563, // 15 minutes
"type": "access"
}
刷新令牌
{
"user": "john_doe",
"iat": 1444262543,
"exp": 1444262563, // 24 hours
"type": "refresh"
}
如您所见,除了生命周期和类型之外,access_token 和 refresh_token 几乎相同。
这是一个问题吗? 以这种方式使用刷新令牌时会出现安全漏洞吗?
PS:这背后的原因是因为我不想将刷新令牌存储在存储(DB/Redis)中。
从安全角度来看,自包含的刷新令牌很容易受到攻击。
我们拥有刷新令牌的原因是为了延长访问令牌的有效性。 换句话说,我们访问了一个授权服务器(或者有一个完全不同的授权流程),使用一些公钥验证它并从服务中获取访问令牌(使用私钥创建)。
刷新令牌必须存储在服务器端。 我们不应该将 JWT 的“自包含”属性用于刷新令牌。 这样做使我们除了更改我们的私钥之外无法撤销刷新令牌。
示例:假设我从我的手机登录到您的应用程序并且它丢失了。 该应用程序包含刷新令牌权限,其中包含我的所有信息。 如果 refresh_token 没有存储在后端,我们就没有办法使该会话无效。 现在需要更改创建令牌的私钥,这不好。
从 refresh_token 创建 access_token 的更高级别的步骤可能是这样的:
让我们先打好基础:
数据库中的令牌表可能包含以下字段:
user_id<uuid>: id of the user
access_token<text>: access token
access_token_expiry<date>: access token expiring timestamp
refresh_token<text>: refresh token (sha)
refresh_token_expiry<date>: refresh token expiring timestamp
refresh_count: number of times the refresh token has been used to access access_token (just in case if you need this field)
请注意,我们应该将刷新令牌的哈希值存储在数据库中。
此外,一个用户可能有多个会话,假设他们从同一设备/不同设备上的不同浏览器登录到我们的应用程序。 为了满足这个需求,我们需要创建一个 login_sessions 表
id<BIGINT>: primary key for the table
user_id<uuid>: id of the user who logged in
map_id<uuid>: This will be the key which maps one access token to its refresh token counterpart. Both tokens of the pair will contain this id in their body.
status<String>: could be ACTIVE|INACTIVE(logged out, INACTIVE user will not be allowed to get access_token from the refresh_token)
created_on<Date>: timestamp for record created on
modified_on<Date>: timestamp for record modified on
refresh_token 主体:
{
"iss": "ABC Service", (The Issuer of the token)
"sub": "4953fag3-ec5e-4ed3-b09e-d847f3f376c6", (The user_id, subject of the token)
"aud": "UI", (audience who will use the token)
"typ": "refresh", (type)
"iat": 1599326501,
"exp": 1601918501,
"jti": "749c77e5-bac0-43f1-aeea-1618ada0224f", (unique identifier for this token)
"mid": "e392692b-6d77-49a9-9928-ac3c3d5208a3" (unique identifier for access-refresh token pair - refers to map_id in login_sessions table)
}
access_token 主体:
{
"iss": "ABC Service", (The Issuer of the token)
"sub": "4953fag3-ec5e-4ed3-b09e-d847f3f376c6", (The user_id, subject of the token)
"aud": "UI", (audience who will use the token)
"typ": "access", (type)
"iat": 1599326501,
"exp": 1599412901,
"jti": "3d2985ef-e767-495e-af88-448fc0ecb167", (unique identifier for this token)
"mid": "e392692b-6d77-49a9-9928-ac3c3d5208a3", (unique identifier for access-refresh token pair - refers to map_id in login_sessions table)
}
"fname": "john",
"lname": "doe",
"roles": [99b18377-5b4c-4e68-8ff4-bac4aea93bd2]
"other_key": "other_value"
从刷新令牌生成访问令牌:
一旦访问令牌过期,我们点击授权服务器api来获取访问令牌,同时在正文中传递refresh_token(jwt)。 授权服务器将公开此 API,它将接受刷新令牌并执行以下步骤,然后返回访问令牌。
脚步:
1. Verify the refresh_token with public key (whose counterpart private formed the token initially)
2. Pick the mid(map_id) from the token body
3. Get login session record containing this mid from the login_sessions table. Go to next step if there exists some login_session record.
4. If the status of the login_session record is ACTIVE, create one access_token (using the private key) with relevant details in it's body
5. Send back the access token as a response.
如果上面的步骤 1-4 中的任何一个失败,我们会发回带有相关消息的错误响应。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.