node.js에서 비밀번호를 변경하고 로그 아웃하는 동안 JWT를 무효화하는 모범 사례?
비밀번호 / 로그 아웃을 변경하는 동안 db를 누르지 않고 JWT를 무효화하는 모범 사례를 알고 싶습니다.
사용자 데이터베이스를 쳐서 위의 두 가지 경우를 처리하는 아이디어가 있습니다.
1. 비밀번호 변경시 사용자 db에 저장된 비밀번호 (hashed)를 확인합니다.
2. 로그 아웃의 경우 사용자 db에 마지막 로그 아웃 시간을 저장하므로 토큰 생성 시간과 로그 아웃 시간을 비교하여이 경우를 무효화 할 수 있습니다.
그러나이 두 가지 경우는 사용자가 API를 누를 때마다 사용자 db를 누르는 대가로 발생합니다. 모든 모범 사례에 감사드립니다.
업데이트 : 나는 우리가 db를 누르지 않고 JWT를 무효화 할 수 있다고 생각하지 않습니다. 그래서 해결책을 찾았습니다. 나는 내 답변을 게시했습니다. 우려 사항이 있으면 환영합니다.
No Refresh 토큰이 사용되는 경우 :
1. 비밀번호 변경시 : 사용자가 자신의 비밀번호를 변경할 때 사용자 db의 비밀번호 변경 시간을 기록하여 비밀번호 변경 시간이 토큰 생성 시간보다 크면 토큰이 유효하지 않습니다. 따라서 나머지 세션은 곧 로그 아웃됩니다.
2. 사용자가 로그 아웃 할 때 : 사용자가 로그 아웃 하면 별도의 DB에 토큰을 저장합니다 (예 : InvalidTokenDB 및 토큰 만료시 Db에서 토큰 제거). 따라서 사용자는 각 장치에서 로그 아웃하고 다른 장치의 세션은 그대로 유지됩니다.
따라서 JWT를 무효화하는 동안 다음 단계를 따릅니다.
- 토큰이 유효한지 확인하십시오.
- 유효한 경우 invalidTokenDB (로그 아웃 된 토큰이 만료 시간까지 저장되는 데이터베이스)에 있는지 확인합니다.
- 존재하지 않는 경우 사용자 db에서 토큰 생성 시간 및 변경된 암호 시간을 확인합니다.
- 변경된 암호 시간 <토큰 생성 시간이면 토큰이 유효합니다.
위의 방법에 대한 우려 :
- 각 API 요청에 대해 위의 모든 단계를 수행해야하므로 성능에 영향을 미칠 수 있습니다.
갱신 토큰 사용시 : 액세스 토큰 만료 1 일, 갱신 토큰을 평생 유효 기간으로
1. 비밀번호 변경 중 : 사용자가 비밀번호를 변경할 때 사용자의 새로 고침 토큰을 변경합니다. 따라서 나머지 세션은 곧 로그 아웃됩니다.
2. 사용자가 로그 아웃 할 때 : 사용자가 로그 아웃 하면 별도의 DB에 토큰을 저장합니다 (예 : InvalidTokenDB 및 토큰 만료시 Db에서 토큰 제거). 따라서 사용자는 각 장치에서 로그 아웃하고 다른 장치의 세션은 그대로 유지됩니다.
따라서 JWT를 무효화하는 동안 다음 단계를 따릅니다.
- 토큰이 유효한지 확인하십시오
- 유효한 경우 토큰이 InvalidTokenDB에 있는지 확인하십시오.
- 존재하지 않는 경우 userDB에서 새로 고침 토큰으로 새로 고침 토큰을 확인하십시오.
- 같으면 유효한 토큰입니다.
위의 방법에 대한 우려 :
- 각 API 요청에 대해 위의 모든 단계를 수행해야하므로 성능에 영향을 미칠 수 있습니다.
- 새로 고침 토큰은 유효성이 없으므로 해커가 사용하는 경우 여전히 인증이 유효한 경우 요청이 항상 성공하므로 새로 고침 토큰을 무효화하는 방법은 무엇입니까?
참고 : Hanz 가 토큰 기반 인증에서 Refesh 토큰 사용 에서 새로 고침 토큰을 보호하는 방법을 제안했지만 보안 이 유지됩니까? , 나는 그가 말하는 것을 이해할 수 없었다. 도움을 주시면 감사하겠습니다.
따라서 누군가 좋은 제안이 있으면 귀하의 의견을 환영합니다.
업데이트 : 앱이 평생 만료되는 새로 고침 토큰이 필요하지 않은 경우 답변을 추가하고 있습니다. 이 답변은 Sudhanshu ( https://stackoverflow.com/users/4062630/sudhanshu-gaur ) 가 제공했습니다 . 감사합니다 Sudhanshu. 그래서 저는 이것이 최선의 방법이라고 믿습니다.
새로 고침 토큰이 필요하지 않고 액세스 토큰이 만료되지 않은 경우 :
사용자가 로그인 할 때 만료 시간없이 사용자 데이터베이스에 로그인 토큰을 만듭니다.
따라서 JWT를 무효화하는 동안 아래 단계를 따르십시오.
- 사용자 정보를 검색하고 토큰이 사용자 데이터베이스에 있는지 확인합니다. 그렇다면 허용하십시오.
- 사용자가 로그 아웃하면 사용자 데이터베이스에서이 토큰 만 제거합니다.
- 사용자가 암호를 변경하면 사용자 데이터베이스에서 모든 토큰을 제거하고 다시 로그인하도록 요청하십시오.
따라서이 방법을 사용하면 만료 될 때까지 로그 아웃 토큰을 데이터베이스에 저장하지 않아도되며 위의 경우에 필요한 비밀번호를 변경하면서 토큰 생성 시간을 저장할 필요도 없습니다. 그러나이 접근 방식은 앱에 새로 고침 토큰이 필요하지 않고 토큰 만료가없는 요구 사항이있는 경우에만 유효하다고 생각합니다.
이 접근 방식에 대해 우려되는 사람이 있으면 알려주십시오. 귀하의 의견을 환영합니다 :)
데이터베이스를 사용하지 않고 토큰을 임의로 무효화 할 수있는 방법은 없습니다.
여러 장치에서 서비스에 액세스 할 수있는 경우 Approach 2에주의하십시오. 다음 시나리오를 고려하십시오 ...
- 사용자는 iPad, Token 1 발급 및 저장으로 로그인합니다.
- 사용자가 웹 사이트에 로그인합니다. 토큰 2가 발행되었습니다. 사용자가 로그 아웃합니다.
- 사용자가 iPad를 사용하려고합니다. 사용자가 웹 사이트에서 로그 아웃하기 전에 토큰 1이 발행되었으며 토큰 1은 이제 유효하지 않은 것으로 간주됩니다.
데이터베이스 저장소도 필요하지만 새로 고침 토큰 의 아이디어를 살펴볼 수 있습니다 .
또한 유사한 문제, 특정 DB 호출을 절약 할 수있는 특정 IanB의 솔루션에 대한 좋은 SO 토론을 보려면 여기 를 참조 하십시오 .
제안 된 솔루션 개인적으로 이것이 제가 접근하는 방법입니다 ... 사용자 인증, 짧은 만료 (예 : 15 분)의 액세스 토큰 및 훨씬 더 긴 기간 또는 무기한 유효한 새로 고침 토큰으로 발급됩니다. 이 새로 고침 토큰의 레코드를 db에 저장합니다.
Whenever the user is 'active', issue a new auth token each time (valid for 15 mins each time). If the user is not active for over 15 minutes and then makes a request (so uses an expired jwt), check the validity of the refresh token. If it's valid (including db check) then issue a new auth token.
If a user 'logs out' either on a device or through a website then destroy both access refresh tokens client side and importantly revoke the validity of the refresh token used. If a user changes their password on any device, then revoke all their refresh tokens forcing them to log in again as soon as their access token expires. This does leave a 'window of uncertainty' but that's unavoidable without hitting a db every time.
Using this approach also opens up the possibility of users being able to 'revoke' access to specific devices if required as seen with many major web apps.
I am not sure if I'm missing something here but I find that the accepted answer is more complicated than is necessary.
I see that db has to be hit to validate or invalidate a token for each api request, however the total process could have been simpler as I see things here.
Whenever a jwt is created, i.e. during login or change/reset password, insert the jwt with userid into a table and maintain a jti (a uuid number basically) for each jwt. The same jti goes into jwt payload too. Effectively jti uniquely identifies a jwt. A user can have multiple jwts at the same time when the account is accessed from multiple devices or browsers in which case, jti differentiates the device or the user-agent.
So the table schema would be, jti | userId. (and a primary key ofcourse)
For each api, check if the jti is in the table, which means the jwt is a valid one.
When the user changes or resets the password, delete all the jti of that userId from the db. Create and insert a new jwt with a new jti into the table. This will invalidate all the sessions from all other devices and browsers except the one that changed or reset the password.
When the user logsout, delete that particular jti of that user but not all. There would be a Single Login but not a single Logout. So when the user logs out, he shouldnt be logged out from all the devices. However, deleting all the jtis would logout from all the devices too.
So it would be one table and no date comparisons. Also it would be the same case if a refresh token is used or not.
However to minimize the db interference, and possible delays, cache usage would certainly help to ease things on processing time front.
Note: Please reason if you are down voting it.
If a user is changing their password, you're going to hit the db there. But don't want to hit the db for authorization?
I have found the benefits of storing a per user string, and a global shared string hashed together gives us the most flexibility with our JWT implementation. In this particular case I'd store a hash of the password to use with the global string and hash them together for a JWT secret.
I agree solely with @gopinath answer just want to add one thing that you should also remove the change password time when all of your tokens expired for example suppose you have set 3 day expiry time for every token to expire now instead of just normaly saving change password time in database you can also set its expiry time of 3 days because as obviously tokens before this will be expired so no need to check for every token again that whether its expiry time is greater then change password time or not
'developer tip' 카테고리의 다른 글
사용자 지정 (개체) 어댑터로 ListView 필터링 (0) | 2020.11.28 |
---|---|
iOS 용 Unity3d 플러그인 빌드 방법 (0) | 2020.11.28 |
명령 줄에 Maven 리포지토리를 추가 할 수 있습니까? (0) | 2020.11.28 |
단일 스레드 프로그래밍 모델에서 비동기 프로그래밍은 어떻게 작동합니까? (0) | 2020.11.28 |
JavaScript에서 "continue"문이 잘못된 이유는 무엇입니까? (0) | 2020.11.28 |