Spring JWT Refresh Token - 인증 인가의 흐름
같이 보면 좋을 연결된 포스팅들
- 👉 Spring Jwt Refresh Token - 인증 인가의 흐름
- ✔️ [Spring] jwt란 - jwt 내부구조, 동작과정, 스프링에서 파싱하기
- ✔️ [Spring] Spring JWT 인코딩, 디코딩 하기 - Java Json 파싱
사내에서 Refresh Token 관련된 부분의 이슈가 생겨서, 리팩토링 하기전에 문제점에 대해 파악한 부분과 인증과 인가의 흐름을 명확하게 집고 넘어가야겠다는 필요성을 느껴 그에 대한 기록을 남깁니다.
📌 하고자 하는것 : jwt 액세스 토큰이 만료되면 jwt 리프레쉬 토큰으로 액세스 토큰 발급
📌 문제 : 액세스 토큰 만료 후, Controller 에서 principal 객체로 로그인 한 사람을 가져올려고하는데 null 이 들어오는 상태
- 문제점 파악 👉 액세스토큰이 만료하면 - 로그인이 안된상태...!!!!!!!!!!
문제점을 파악하고 나니. "그렇다면 AccessToken 을 Refresh 하게 발급해줄려면 어떤 과정을 거쳐야 안전하게 보낼 수 있지?" 라는 의문이 들어 인증과 인가의 과정부터 시작하여, Token을 발급받아 인증과 인가를 받아오는 과정까지 다시 공부해보았습니다.
- 이전 포스팅 "[Spring] 웹의 인증,인가 /쿠키와 세션"
[목차]
- 인증 인가
- HTTP로 인증하는 방법 - Basic 인증
- 서버로 조금 더 안전하게 인증하는 방법
- Token을 이용해서 효율적으로 인증하는 방법
- Refresh Token 과 토큰 정책
1. 인증이란
- 식별 가능한 정보로 서비스에 등록된 유저의 신원을 입증하는 과정입니다.
ex)
1. 내가 푸드 건물에 입장할 수 있도록 건물앞에서 인증한다.
2. 사용자가 서비스를 사용할 수 있도록 인증한다.
2. 인가란
- 인가란, 권한에 대한 허가입니다.
- 즉, 인증된 사용자에 대한 자원 접근 권한 확인을 말합니다.
ex)
1. 내가 푸드 건물에 들어가서 화장실도 가고, 업무도 볼순 있지만, 보안실에는 들어가지 못한다.
2. 사용자가 구매한 상품에 대해 리뷰를 작성할 순 있지만, 다른 사용자의 리뷰를 지울 수 있는 권한은 없다.
👉 이렇게 사용자의 권한을 나타내는 것을, 사용자에 대한 인가라 합니다.
즉, 선행되어야한 것은 인증 ➡️ 인가 의 순으로 진행되어야 합니다.
3. 인증받는 방법
유저가 인증받는 방법은, 로그인이라고 말할 수 도 있습니다.
이제 로그인을 하는 과정에 대해서 순서대로 알아 보겠습니다!!
1) Request Header
- 가장 단순한 방식입니다. Reqest Header 에 사용자 정보를 넣어서 API 요청시 정보를 같이 보내는 것입니다.
Basic 인증방식이라도 하며, 사용자의 정보를 Base64로 인코딩 된 문자열을 Authorization: Basic <credentials> 에 넣어서 보내주는 개념입니다.
- 이렇게 Http 에 정보를 담아 서버에 요청을 보내고
- DB의 사용자 정보를 체크해, 인증해 줍니다.
🙌 Request Header 만 활용했을 때의 단점
- 매 요청마다 사용자가 인증해야한다.
- 정보를 탈취당하거나, 패킷 도청을 당할 위험이 매우매우 높다.
이러한 단점을 해결하기 위해 Browser 의 Storage 의 힘을 빌려서 해결할 수 있습니다.
4. 인증 유지하기
1) Browser
Browser 의 Storage 에는, Local Storage, 쿠키, 세션 등이 존재합니다.
사용자의 매 요청마다, 인증정보를 입력하지 않도록 하기위해,
이러한 Browser 의 Storage 에 사용자 정보를 저장해두었다가, 인증정보가 필요할 때마다
저장된 정보를 꺼내서 보내는 방식입니다.
장점
- 사용자의 입장에서 굉장히 편리합니다.
- 한번 정보를 저장하고 나면, 더이상 클라이언트의 입장에서는 인증에 대해서 신경쓰지 않아도 됩니다.
단점
- 해커의 입장에서도 굉장히 편리합니다.
- 클라이언트는 상대적으로 서버보다 보안에 취약할 수 밖에 없습니다.
- Storage에 저장한다는 것은, 정말 단순하게 행으로된 정보를 저장한다는 것이기 떄문에 매우 보안에 취약합니다.
5. 안전하게 인증하기
Server
- 이러한 보안적 이슈를 해결하기 위해, Server 를 이용할 수 있습니다.
1) Session
세션이란, 사용자가 정보를 인증하면, 사용자의 정보를 클라리언트가 그대로 가져가는게 아닌,
임의의 문자열로 서버에서 세션 ID를 만들어 사용자에게 세션 ID를 저장하고 있도록 하는 방법입니다.
장점
- 클라이언트가 날것의 정보를 raw한 데이터로 저장하지 않기 때문에, 정보를 탈취당해도 위험이 적습니다.
- 세션의 만료기간을 저장할 수 있기 때문에, 이것또한 보안상의 이점을 가져갈 수 있습니다.
단점
- 서버에서 세션 ID를 관리해주어야하기 때문에 데이터의 관리를 해주어야합니다.
(그리 큰 단점이라고는 생각되지 않긴합니다..ㅎ) - 서버가 한대가 아닌 여러대로 나누어져있는 상황이라면 (ex - 로드밸런싱) 1번 서버에서 세션 ID를 발급받았는데, 다음 요청에서는 2번 or 3번 서버로 요청을 보낸다면, 세션 정보는 1번 서버에만 세션 아이디 값이 있기 때문에 에러가 납니다.
- 이러한 문제점을 해결하기 위해, 세션 스토리지를 사용합니다.
- 모든 서버의 세션을 한 곳에서 두어서 해결하기 위한 것입니다.
- 요청이 너무 많아지면, 서버가 많아질 수 록 많은 요청을 보내기 때문에 서버거 터질수도 있습니다.
6. 효율적으로 인증하기
클라이언트, 서버, 세션에 한번씩 사용자의 정보를 맡겨보니 문제가 계속 생겼습니다.
따라서 이번에는 정보의 흐름에 맡겨보자..! 해서 나온게 바로 Token 입니다.
1) Token
정보의 요청과 응답안에 Token을 이용해서 사용자의 상태를 담고, 그것을 이용해서 인증과 인가를 처리하는 것이 Token을 이용한 인증과 인가 방법입니다.
2) JWT
- Jwt 란, Json Web Token의 약자 입니다.
JWT는 시크릿 키를 활용하여 JWT를 발급받고, 시크릿 키를 사용해서 JWT 의 인증 과정을 거칩니다.
- 사용자 정보를 바탕으로 인증이 되면, 시크릿 키를 활용해서 JWT 를 사용자에게 보냅니다.
- 사용자는 다음 요청에 이 JWT 를 보내고 서버에서 시크릿키만을 이용해서 JWT의 토큰의 유효성을 체크합니다.
- 유효한 토큰이라면 사용자 인증을 거칩니다.
- 그 다음, 토큰의 만료기간을 체크하고
- 권한을 체크합니다.
장점
세션과 달리, 서버가 가진 시크릿 키를 이용하기 때문에, 서버의 부하와 서버가 여러대가 늘어나도 각각 똑같은 방법으로 인증과 인가가 진행되기 때문에 서버 확장성에 대한 이점을 가져갈 수 있습니다.
단점
- 똑같이, 해커가 Jwt 를 탈취하면 모든 걸 할 수 있습니다.
- 이러한 문제점을 해결하기 위해 JWT 토큰의 만료기간을 보통 짧게 가져갑니다.
- 토큰의 만료기간을 짧게 가져가는 대신 Refresh Token 을 이용하는 방법이 있습니다.
3) Refresh Token
- 토큰이 만료되었다면, 사용자의 인증이 끝다는 말입니다.
- 즉 로그아웃이 되었기 때문에, 사용자는 다시 로그인을 해야합니다.
- 이러한 과정이 너무 짧은 주기로 이루어진다면 사요자의 사용성이 저하되기 때문에 Refresh Token 이라는 개념이 나왔습니다.
4) Refresh 과정
- 사용자는 액세스 토큰이 만료되었을 때 요청을 보내서 만료 됬다는 응답을 받으면
- 클라이언트에서 다시, 액세스 토큰과 리프레쉬 토큰을 서버에 보냅니다.
- 서버에서는 리프레쉬 토큰이 유효하다면, 클라이언트에게 다시 새로운 액세스 토큰을 발급해줍니다.
7. 토큰 정책
사실 Refresh Token 에 대해서는 Jwt 액세스 토큰의 보안을 위해 나온 개념이기 때문에 딱, 이게 정답이다! 라는 정보가 없습니다.
[글로벌 회사들의 토큰 정책]
- 액세스 토큰을 발급할 때, Refresh 도 새로 발급해서, 계속계속 보안성을 가져가면서 무한 로그인을 유지한다던가
- Refresh 의 기간이 끝나면 새로 로그인을 하도록 한다던가
- Refresh를 아예 사용하지 않는다거나 (애플의 정책)
- Refresh를 사용하지 않으면서 액세스 토큰을 short-term, long-term 2가지로 분리한다거나 (페이스북)
- 서비스에서 관리하는 고유한 키값으로 토큰을 재발급 받는다거나 (Google)
[Oauth 2.0 rfc 문서에 나온 Token Refresh 의 과정]
authorization information. Unlike access tokens, refresh tokens are
intended for use only with authorization servers and are never sent
to resource servers.
+--------+ +---------------+
| |--(A)------- Authorization Grant --------->| |
| | | |
| |<-(B)----------- Access Token -------------| |
| | & Refresh Token | |
| | | |
| | +----------+ | |
| |--(C)---- Access Token ---->| | | |
| | | | | |
| |<-(D)- Protected Resource --| Resource | | Authorization |
| Client | | Server | | Server |
| |--(E)---- Access Token ---->| | | |
| | | | | |
| |<-(F)- Invalid Token Error -| | | |
| | +----------+ | |
| | | |
| |--(G)----------- Refresh Token ----------->| |
| | | |
| |<-(H)----------- Access Token -------------| |
+--------+ & Optional Refresh Token +---------------+
Figure 2: Refreshing an Expired Access Token
The flow illustrated in Figure 2 includes the following steps:
(A) The client requests an access token by authenticating with the
authorization server and presenting an authorization grant.
(B) The authorization server authenticates the client and validates
the authorization grant, and if valid, issues an access token
and a refresh token.
(C) The client makes a protected resource request to the resource
server by presenting the access token.
(D) The resource server validates the access token, and if valid,
serves the request.
(E) Steps (C) and (D) repeat until the access token expires. If the
client knows the access token expired, it skips to step (G);
otherwise, it makes another protected resource request.
(F) Since the access token is invalid, the resource server returns
an invalid token error.
[문서에 같이 나온 Refresh Token 이용 방침?]
경우에 따라서 리프레쉬 토큰으로 액세스토큰을 발급받을 때, refresh token 도 재발급 받을 수 도 있고, 아닐 수 도 있다,
애플과 페이스북
등등,, Refresh Token의 구현 방법은, 각 서비스와 상황에 맞는 토큰 정책을 먼저 생각한 다음의 문제라는 것을 알게되었습니다
한번 최선의 정책을... 생각해보거는거로오 야하호..
*참고
- 우테코 인증과 인가 : https://www.youtube.com/watch?v=y0xMXlOAfss
- 구글의 토큰 정책 : https://developers.google.com/identity/protocols/oauth2/web-server#httprest_2
- oauth 2.0 rfc 문서 : https://www.rfc-editor.org/rfc/rfc6749#section-1.5
- 여거 시리즈 좋은 내용 같음 : https://velog.io/@tlatldms/%EC%84%9C%EB%B2%84%EA%B0%9C%EB%B0%9C%EC%BA%A0%ED%94%84-Refresh-JWT-%EA%B5%AC%ED%98%84#%EB%A1%9C%EA%B7%B8%EC%95%84%EC%9B%83-%EC%A0%95%EC%B1%85