繁体   English   中英

JWT 刷新令牌。 可以自给自足吗?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM