이 글에서는 JWT에 대해 정리해보겠습니다.
1. 세션 인증
JWT 에 대해 살펴보기에 앞서, 먼저 세션을 통한 인증 방식에 대해 간단하게 살펴보겠습니다.
세션을 이용한 인증은 서버 측에서 사용자의 정보를 저장하여 이뤄집니다.
세션을 이용하면 저장과 삭제를 통해 꽤나 간편하게 로그인 과정을 처리할 수 있습니다.
1. 로그인 요청
2. 로그인 처리 -> 세션에 사용자 정보 저장
3. 로그아웃 요청 -> 세션에서 사용자 정보 제거
세션은 사용자의 정보가 서버에서 보관되는 방식이기 때문에, 보안상으로 안전한 편입니다.
참고로 기본적으로 세션은 서버의 메모리에 사용자의 정보를 저장합니다. 다만 메모리의 단점을 극복하기 위해 하드 디스크나, DB까지 다양하게 사용한다고 합니다.
2. JWT
(1) JWT란?
세션 방식은 편리하지만 크게 2가지 정도 단점이 존재합니다.
- 사용자가 많아질수록 서버의 부담이 늘어난다
- REST API의 원칙을 위반한다.
(※서버에서 state를 저장하기 때문에 원칙상으로는 위반하기는 하지만, REST API 원칙을 위반하는 것이 단점은 아니라는 의견이 많습니다.)
이를 극복하기 위해 사용자에게 토큰을 발행하고, 그 토큰을 통해 인증하는 방식이 등장하였고,
이때 주로 사용되는 토큰의 형식이 JWT(JSON Web Token)입니다.
토큰은 '티켓' 과 비슷하다고 생각하면 됩니다.
사용자가 티켓을 들고와서 인증을하면 되므로, 서버는 별도로 인증을 위한 정보를 저장할 필요가 없는 것이죠. 0
(2) JWT 구조
JWT는 크게 헤더, 페이롣, 시그니처 3가지 부분으로 이뤄져 있습니다.
ex) 2Efer6.TU213.feEe21

① 페이로드
가장 먼저 페이로드는 사용자의 정보가 인코딩된 부분입니다.
이 부분을 디코딩하면 아이디나, 닉네임 권한 등의 정보를 얻을 수 있습니다.
서버는 페이로드를 보고, 어떤 사용자인자 파악하게 됩니다.
편하기도 하지만 한편으로는 보안상으로 위험해보입니다.
만약 의도적으로 JWT의 페이로드를 수정하면, 다른 사용자로 인증할 수 있을까요?
헤더와 시그니처가 보안을 위해 존재합니다.
② 헤더
우선 헤더에는 암호화 알고리즘이 표시되어 있습니다.
(타입도 표시되고, 이는 JWT로 고정입니다.)
③ 시그니처
티켓을 가져오더라도, 위조 티켓인지 아닌지 검사 정도는 해야 합니다. 검사를 위해 서버는 비밀키를 이용합니다.
여기서 검수는 다음과 같습니다.
헤더와 페이로드 그리고 서버의 비밀키를 조합하여 암호화 알고리즘으로 암호화한 결과가 시그니처와 일치해야 합니다.
만약 사용자가 의도적으로 페이로드나 헤더를 수정하면, 수정된 토큰으로 검수(헤더, 페이로드와 비밀키와 조합 후 암호화)하면 시그니처와 일치하지 않으므로, 인증에 실패하게 됩니다.
그렇다면 시그니처 자체를 위조하면 될까요?
헤더와 페이로드 그리고 시그니처까지 통째로 한 사용자에 맞춰서 변경하면 될 것도 같지만, 서버의 비밀키까지 조합해야 시크니처가 나오는 것이기 때문에, 서버의 비밀키를 모른다면 시그니처를 생성할 수도 없는 것이죠.
그렇기 때문에, 서버의 비밀키는 외부로 노출되면 안됩니다!
(3) Refresh token
그런데 여전히 한가지 문제가 남아있습니다. 해커가 JWT 자체를 탈취하면 서버 입장에서는 그 사용자를 차단할 방법이 없습니다.
티켓을 들고 온 사람이 발급 받은 사람인지, 티켓을 주운 사람인지 확인할 방법이 없는거죠. 또 이미 발급한 티켓을 무효화할 수도 없습니다.
이를 해결하기 위한 방법이 access token과 refresh token, 2종류를 발급하는 것입니다.
Refresh token은 access token을 재발급 받기 위한 토큰입니다. 그렇기 때문에 access token과 달리 사용자의 정보를 구체적으로 담고 있지는 않고, 재발급 받기 위한 정보만 보유하고 있습니다.
또 다른 특징으로는 refresh token은 결국 DB에 저장됩니다.
우선 refresh token을 이용할 때의 흐름을 살펴보겠습니다.
- access token과 refresh token을 함께 발행
- access token의 만료기간을 짧게 설정
-> access token은 넘어가더라도, 금방 만료됩니다. - access token이 만료되었더라도, refresh token이 유효하다면 다시 access token 발행
-> refresh token의 유효기간은 길게 설정합니다.
핵심은 'access token'의 유효기간을 짧게 하는 것, 'refresh token은 DB에서 관리하는 것' 2가지 입니다.
먼저 access token의 유효기간을 짧게 함으로써, access token이 탈취되어도 오래 사용할 수 없습니다.
Refresh token 자체가 탈취 당할수도 있습니다. 그러한 경우는 refresh token을 DB에서 삭제하면 됩니다. 이러면 refresh token을 통해 access token을 발급 받을 수 없게 됩니다.
단, refresh token을 이용하면 보안 상으로 좀 더 안전하게 토큰을 이용할 수 있지만, 결국 서버측에서 인증 정보를 저장해야 하는 점에서 토큰 방식의 장점이 어느 정도 장점이 상쇄되는 것도 사실입니다.
(4) 토큰 관리
처음 JWT를 접할 때 헷갈렸던 부분은 토큰을 저장하는 위치였습니다.
토큰을 처음 발급 받고 나면, 어디에 저장해야 할까요?
① localStorage
먼저 JWT를 localStorage에 저장해두는 방법이 있습니다.
쉽게 저장하고 관리할 수 있겠지만, 여러 자료를 찾아본 결과 이는 권장하지 않습니다.
그 이유는 XSS 공격에 취약하기 때문이죠. 간단하게 설명하면 JS를 통해 쉽게 접근할 수 있습니다.
(XSS 공격)
② Cookie
결론적으로 쿠키에 저장하는 것이 현재로서 가장 권장되는 방법인 듯 합니다.
정확히는 HttpOnly 옵션과 same-site 속성을 설정한 쿠키로 저장하는 것입니다.
- XSS
우선 HttpOnly 옵션을 설정하면, XSS 공격에 안전합니다.
- CSRF
기본적으로 쿠키는 CSRF 에 취약합니다. (CSRF 공격)
그러나 same-site 속성이나 referer 검사 등을 통해서 예방할 수 있습니다.
물론 이렇게 쿠키를 이용하더라도 완전히 안전한 것은 아니라고 합니다.
저장 위치에 앞서 결국 서비스 자체에서 XSS나 CSRF 공격을 차단하는 것이 중요합니다.
'개발' 카테고리의 다른 글
[CI/CD] (2) CD 흐름 파악하기(AWS Code Deploy) (0) | 2023.05.04 |
---|---|
[CI/CD] (1) Github actions로 CI 구축하기 (1) | 2023.04.20 |
[Git] 하나의 저장소에 여러 프로젝트 추가하기(subtree) (0) | 2023.04.12 |
[REST API] 리스트를 JSON으로 반환할 때 주의할 점 (0) | 2023.04.10 |
[Web] OAuth 2.0 (0) | 2023.03.28 |