jwt 刷新令牌
Nowadays security schema that lays on two tokens quite common. There are a lot of information about theme in the Internet. There are often only description what is Refresh and Access tokens and how to usem.
如今,基于两个令牌的安全模式非常普遍。 Internet上有很多有关主题的信息。 通常仅描述什么是刷新和访问令牌以及如何使用。
To understand concept behind tokens I would like to do one simple thought experiment.
为了理解令牌背后的概念,我想做一个简单的思想实验。
Let’s imagine that you are a student that likes money but often has around zero on his account balance.
假设您是一个喜欢钱的学生,但账户余额通常约为零。
On the way to your university you open your bank mobile application to check your account balance.
在去大学的路上,您打开银行移动应用程序以检查您的帐户余额。
To show you a balance application needs to execute request to the bank server:
为了向您显示余额应用程序需要执行对银行服务器的请求:
GET http://api.mybank.com/balance HTTP 1.1
and receives response
GET http://api.mybank.com/balance HTTP 1.1并收到响应
{ balance: '$0.0' }
{ balance: '$0.0' }
Would be good if no one except you could check your bank account. To do so, let’s add special header with user name and your unique password:
如果没有人可以检查您的银行帐户,那将很好。 为此,让我们添加带有用户名和唯一密码的特殊标头:
`Authorization: Username Password
`授权:用户名密码
Authorization: JohnDwayson QWERTY1`
授权:JohnDwayson QWERTY1`
Now server can authenticate you by your personal username and password. It means that pair JohnDwayson QWERTY1 needs to be kept in a secret place on your mobile phone to be protected from someone who not allowed to spend your money. Would even better if we could avoid storing password but no one wants to enter it too often.
现在,服务器可以通过您的个人用户名和密码对您进行身份验证。 这意味着,JohnDwayson QWERTY1对必须保存在手机上的秘密地方,以保护免受不允许花钱的人的侵害。 如果我们可以避免存储密码,但是没有人想输入太多,那就更好了。
When we are using our mobile application for the 30 minutes in a bus, it will send your password over network many times in 30 minutes.
当我们在公共汽车上使用我们的移动应用程序30分钟时,它将在30分钟内多次通过网络发送您的密码。
Every requset contains password Let’s continue our thought experiment. You are still in a bus and your app sends request to the server.
每个requset都包含密码让我们继续进行思想实验。 您仍然在公共汽车上,您的应用程序将请求发送到服务器。
What if a fraud is sitting around you in a bus and he can intercept one or few http packets from your mobile phone to the bank server?
如果欺诈行为在您周围坐着公共汽车,并且他可以拦截从您的手机到银行服务器的一个或几个HTTP数据包,该怎么办?
If app updates information every minute, fraud will have 30 possibilities to intersect requests and get your password.
如果应用程序每分钟更新一次信息,则欺诈将有30种可能使请求相交并获取密码。
Let’s assume he stole 5–6 messages. Your password now is compromised and fraud can use it to access your account information.
假设他偷了5-6条消息。 现在您的密码已被盗用,欺诈者可以使用它来访问您的帐户信息。
Man in the middle can overhear the password What can he do with this information? Good news that he cannot spend your money as you don’t have it … yet :) He also cannot change your password as in this case you will notice that and can use SMS from a bank to recover the password. Old stolen password in this case will no longer be valid and student will save his money
中间的人可以窃听密码,他可以使用此信息做什么? 好消息是他不能花你的钱,因为你没有钱... :)他也无法更改密码,因为在这种情况下,您会注意到这一点,并且可以使用银行的SMS来恢复密码。 在这种情况下,旧的被盗密码将不再有效,学生将省钱
But what he can do is to keep checking your balance in parallel with you. He can easily write a Python script that will check your account every 10 seconds and as soon as you will receive money he can spend every single cent for buying bitcoins. Probably even worse case if his script will spend 5–10 buks every day, and it is likely will not be noticed for the months or years.
但是他能做的就是与您同时检查您的余额。 他可以轻松编写一个Python脚本,该脚本每10秒检查一次您的帐户,一旦您收到付款,他就可以花每一分钱购买比特币。 如果他的剧本每天花费5到10布克,甚至更糟的情况发生,可能几个月或几年都不会被注意到。
Hacker waits for your money To avoid this, we can ask user to change his password after some time. Let’s say password will be valid on for 3 months. Good thing is that after 3 month he will lose access to your account. Bad thing is that he will lose access to your account only after 3 months. Obviously, to avoid this we can ask you to change your password every month or week. But it can be annoying for the end users.
黑客在等您的钱为了避免这种情况,我们可以要求用户在一段时间后更改密码。 假设密码有效期为3个月。 好消息是,三个月后,他将失去对您帐户的访问权限。 不幸的是,他只会在3个月后失去对您帐户的访问权限。 显然,为避免这种情况,我们可以要求您每月或每周更改一次密码。 但这对于最终用户可能会很烦。
Would be good if we will not use our password too often in our requests. To do so we can introduce special endpoint: http://api.mybank.com/login. We are going to send our credentials only to this endpoint and in return server will generate for us special token. Let it be just unique string, GUID, that server stores in his database. Let’s call this unique string is Access token. We will use it instead of our username and password in header of every request talk with server. Similar to password let’s set expiration time for the access token.
如果我们在请求中不经常使用密码,那就太好了。 为此,我们可以引入特殊的端点: http : //api.mybank.com/login 。 我们将仅将凭据发送到此端点,作为回报,服务器将为我们生成特殊令牌。 让它只是服务器存储在其数据库中的唯一字符串GUID。 我们将此唯一字符串称为Access令牌。 在与服务器进行的每个请求对话的标题中,我们将使用它代替我们的用户名和密码。 与密码类似,让我们设置访问令牌的到期时间。
To update balance we don’t need a password Let’s reproduce our thought experiment.
要更新余额,我们不需要密码。让我们重现我们的思想实验。
We are in the bus and someone stole our http request to check balance. But now fraud has access token only.
我们在公共汽车上,有人偷走了我们的http请求以检查余额。 但是现在,欺诈仅具有访问令牌。
It’s not enough to steal only access token What hacker can do now with this information? First of all, he still cannot spend your money. Second is he cannot change password as simply he doesn’t know it. Also, now the expiration time for the password and access token is two separate settings. We can leave password expiration time as 3 months and we need to choose access token expiration. We would like to set this time as short as possible, because to get new access token we cannot use token itself. If someone will steal this token he will able to renew it as long as he wants.
仅窃取访问令牌是不够的,黑客现在可以利用此信息做什么? 首先,他仍然不能花你的钱。 其次,他不能更改密码,因为他根本不知道密码。 另外,现在密码和访问令牌的到期时间是两个单独的设置。 我们可以将密码的有效期保留为3个月,我们需要选择访问令牌的有效期。 我们希望将此时间设置得尽可能短,因为要获取新的访问令牌,我们不能使用令牌本身。 如果有人窃取了此令牌,他将能够根据需要续签该令牌。
When access token is expired, to get a new one we need to send user credentials again. If you are in a bus for the 30 minutes and your expiration time for the access token is 15 minutes you need to send your password at least 2 times. Usually we want to update access token earlier, let’s say every 10 minutes, otherwise user may notice some delays to obtain new token. Also, it solves issue when few requests at the same time are failed because of the expired token and we need to retry them in a right order after obtaining new token.
访问令牌过期后,要获取新令牌,我们需要再次发送用户凭据。 如果您在公交车上停留30分钟,并且访问令牌的有效时间为15分钟,则需要至少两次发送密码。 通常,我们希望更早地更新访问令牌,例如每10分钟更新一次,否则用户可能会注意到获取新令牌的一些延迟。 此外,它还解决了由于令牌过期而导致同时有几个请求失败而导致的问题,我们需要在获取新令牌后以正确的顺序重试它们。
Now results are better. Fraud has access to our data only for the 10 minutes instead of 3 months. But he still has good change to steal our password and we may not notice this until he steals our money.
现在效果更好。 欺诈仅在10分钟(而不是3个月)内访问我们的数据。 但是他仍然可以窃取我们的密码,而且在他窃取我们的钱之前,我们可能不会注意到这一点。
The issue now is to obtain access token we still need the password. What if we will generate one more unique string. A special token used just to obtain access token.
现在的问题是要获取访问令牌,我们仍然需要密码。 如果我们将再生成一个唯一的字符串,该怎么办。 一种特殊令牌,仅用于获取访问令牌。
To achieve this our login endpoint should accept username and password and returns new token called Refresh token. Which we will store in our mobile app. Refresh token can have longer expiration time, for example a month.
为此,我们的登录端点应接受用户名和密码,并返回称为“刷新令牌”的新令牌。 我们将存储在我们的移动应用程序中。 刷新令牌的到期时间可能更长,例如一个月。
Renew flow for refresh and access tokens Every time we need to renew access token we need to send just refresh token. So our password will be sent to the server only once in a month or ever more rarely. Basically we just need password only to retrieve first Refresh token.
刷新流以刷新和访问令牌每次我们需要更新访问令牌时,我们只需要发送刷新令牌。 因此,我们的密码只会在一个月内发送一次到服务器,甚至很少。 基本上,我们只需要密码即可检索第一个刷新令牌。
We still need access token to execute requests to obtain some data from the server. So:
我们仍然需要访问令牌来执行请求以从服务器获取一些数据。 所以:
POST /login with username and password returns us refresh token
POST /renew with refresh token returns us access token
POST /balance with access token returns us actual balance
POST /login with username and password returns us refresh token POST /renew with refresh token returns us access token POST /balance with access token returns us actual balance
Let’s replay our experiment again.
让我们再次重播我们的实验。
We are in a bus. Our student is checking his balance.
我们在公共汽车上。 我们的学生正在检查他的余额。
But now our application uses refresh token that stored somewhere in a file on mobile phone.
但是现在我们的应用程序使用刷新令牌,该令牌存储在手机文件中的某个位置。
Application is sending requests like:
应用程序正在发送如下请求:
POST /renew
GET /balance
GET /balance
GET /balance
POST /renew
GET /balance
GET /balance
GET /balance
POST /renew GET /balance GET /balance GET /balance POST /renew GET /balance GET /balance GET /balance
As earlier, hacker is intersected few requests with access token in a bus.
如前所述,黑客在总线中与访问令牌相交的请求很少。
As expiration time for the access token is 15 minutes and we are updating tokens every 10 minutes.
由于访问令牌的到期时间为15分钟,因此我们每10分钟更新一次令牌。
Hacker can use stolen information only for 10 minutes or less.
黑客只能在10分钟或更短的时间内使用被盗的信息。
What if he intersected one of the /renew requests and have refresh and access token? Theoretically he can use refresh token for a month to obtain new access tokens and still be able to stole money.
如果他与/ renew请求之一相交并具有刷新和访问令牌怎么办? 从理论上讲,他可以使用刷新令牌一个月来获取新的访问令牌,并且仍然能够偷钱。
But if we will regenerate both tokens on every /renew request and server stores only one refresh token at a time. Fraud’s copy of refresh token also became invalid in a 10minutes and he cannot use it without letting us know that token is compromised. If he will try to renew token, it will invalidate our token and we will be forced to relogin.
但是,如果我们将在每个/ renew请求中重新生成两个令牌,并且服务器一次仅存储一个刷新令牌。 欺诈的刷新令牌副本也将在10分钟内失效,并且他不能在不通知我们令牌已被盗用的情况下使用它。 如果他尝试续签令牌,它将使我们的令牌无效,我们将被迫重新登录。
One more advantage of refresh token is that we don’t need to store password in a application or browser and store only last refresh token instead.
刷新令牌的另一个优点是,我们不需要在应用程序或浏览器中存储密码,而只存储最后一个刷新令牌。
Interesting thing is that access token can be not just a random string, but can contain some useful information. For example, it can be expiration time, user ID and user role. In this case it is called self-contained token and server doesn’t need database access to validate token and user permissions. It can be very useful in microservices as it can increase performance and decrease coupling between microservices.
有趣的是,访问令牌不仅可以是随机字符串,还可以包含一些有用的信息。 例如,可以是到期时间,用户标识和用户角色。 在这种情况下,它称为自包含令牌,服务器不需要数据库访问即可验证令牌和用户权限。 它可以在微服务中非常有用,因为它可以提高性能并减少微服务之间的耦合。
It's a bit out of article theme but it is worth to mention scope.
What if we will ask /renew endpoint only for access token that can be used exclusively for checking balance?
If the user wants to spend some money he should receive additional different second token for that? We can call this parameter 'scope'.
So we can ask to /renew?scope=[balance, news]. If our hacker stills this token he cannot use it to spend our money!
它有点不符合文章主题,但值得一提的是scope 。 如果我们仅向/ renew端点询问仅可用于检查余额的访问令牌怎么办? 如果用户想花一些钱,他应该为此获得其他不同的第二令牌吗? 我们可以将此参数称为“作用域”。 因此,我们可以要求/ renew?scope = [balance,news]。 如果我们的黑客仍然使用此令牌,他将无法使用它来花费我们的钱!
Idea based on two tokens gives use better safety than just password or one token by design. In opposite of choosing longer password or stronger security algorithms.
与仅设计密码或一个令牌相比,基于两个令牌的思想可以提供更好的安全性。 与选择更长的密码或更强的安全性算法相反。
This was my explanation for basic concept behind tokens and how they work.
这是我对令牌背后的基本概念及其工作原理的解释。
On a practice there is a few different implementations of this concept that can be easily googled.
在实践中,可以很容易地用谷歌搜索这个概念的几种不同实现。
Small note about flexibility in choosing an expiration time for the password and tokens.
关于灵活选择密码和令牌的到期时间的小注释。
Typical expiration time can be:
典型的到期时间可以是:
For the password it is 3–6 months. It is good to have this limitation. As databases can be stolen and user can reuse same password across services.
密码为3到6个月。 最好有这个限制。 由于数据库可能被盗,用户可以跨服务重复使用相同的密码。
For the refresh token expiration time can be about a week or month. For the people who is working in an office with some website it is useful to have this time at least longer than a weekend. Otherwise they need to enter password every Monday.
对于刷新令牌,到期时间可以约为一周或一个月。 对于在办公室中拥有一些网站的人们来说,这段时间至少要长于周末是很有用的。 否则,他们需要在每个星期一输入密码。
Access token expiration time can be in a range from 10 to 60 minutes. Shorter time requires more requests for renewal but longer time can give more chances for the fraud.
访问令牌的到期时间可以在10到60分钟之间。 时间越短,需要的续约请求就越多,但是时间越长,欺诈的机会就越多。
Conclusion:
结论 :
We need to use password to obtain long lived refresh token. Then send refresh token to obtain short lived access token. Than utilize access token to execute useful requests.
我们需要使用密码来获取长寿的刷新令牌。 然后发送刷新令牌以获得短暂的访问令牌。 比利用访问令牌执行有用的请求。
jwt 刷新令牌