프로젝트를 진행하면서 로그인 인증을 구현하게 되었는데 JWT(Json Web Token)라는 인증방식을 사용하게 되었는데 최근에 가장 많이 쓰이는 방식이기도 하고 보안 관련한 지식이 필요하다고 생각되어 포스트로 정리하기로 했다 🏃♂️
토큰 기반의 인증 시스템인 JWT에 대해 다루기 전에 서버 기반 인증 시스템에 대해서 먼저 알아보자.
서버 기반 인증 시스템이란 과거에 주로 사용하던 인증 시스템으로, 유저들에 대한 정보를 서버쪽에서 Session을 이용하여 기억하던 방식이다. 이러한 서버를 Staeful 서버라고 한다.
서버에선 유저의 정보를 기억하기 위해서 Session을 유지시켜야 했는데 이때 메모리, 디스크, 데이터베이스 등을 통해 관리했다.
위와 같이 서버 기반 인증 시스템은 유저가 로그인을 시도하면 Session에 유저 정보를 저장하고 Session을 유지하며 서비스를 제공할때 해당 정보를 사용하는 방식이다.
이러한 방식의 인증 시스템은 소규모 프로젝트의 경우에는 큰 문제 없이 유지가 되겠지만 유저가 늘어나고 대규모 프로젝트가 된다면 아래와 같은 문제점이 발생한다.
1. 서버 부하
보통의 경우 Session을 메모리에 저장하는데, 만약 유저가 늘어나는 경우 서버의 RAM에 무리를 주게 된다. 이를 피하기 위해 DB에 저장하기도 하는데 이 경우에도 DB에 무리를 줄 수 있다.
2. 확장성
서버의 사이즈가 커져서 여러대의 서버를 사용하게 되면 분산 시스템을 설계하게 되는데 이 과정에서 Session을 사용하면 복잡한 과정을 거쳐야한다.
3. CORS
Session을 사용하면 Cookie를 사용하게 되는데 Cookie는 단일 도메인 및 서브 도메인에서만 동작을 하게 된다. 만약 여러 도메인에서 Session을 사용하게 되면 관리가 어려워진다.
위에서 언급한 서버 기반 인증 시스템의 단점을 보완하기 위해 등장한것이 바로 토근 기반 인증 시스템이며 그중에서도 많이 쓰이는 것이 바로 Json 포맷을 이용하는 JWT(Json Web Token)이다.
(아래에 작성할 토큰 기반 인증 시스템 설명은 JWT를 기반으로 작성했다.)
토큰 기반 인증 시스템은 인증받은 유저들에게 Token을 발급하고, 유저가 서버에 요청사항이 있을 때 요청과 함께 헤더에 Token(Access Token)을 보내도록 하여 서버에서는 유저가 보낸 Token이 서버에서 제공한 Token과 일치하는지 확인하는 인증 과정을 처리한다.
Token을 이용하면 서버 기반 인증 시스템과 달리 상태를 유지하지 않으므로 Stateless한 구조를 가지게 된다.
토큰 기반 인증 시스템은 아래와 같은 과정을 통해 작동하게 된다.
1. 무상태성 & 확장성
토큰은 유저쪽에 저장되기 때문에 서버는 Stateless하며 유저와 서버의 연결고리가 없기 때문에 서버를 확장하기에 매우 적합하다.
2. 보안성
유저가 서버로 요청을 보낼 때 더이상 Cookie를 전달하지 않으므로 Cookie 사용으로 인한 보안 문제점이 더이상 발생하지 않는다.
3. 여러 플랫폼 및 도메인
토큰을 사용하면 어떤 디바이스, 어떤 도메인에서도 토큰의 유효성 검사만을 진행한 후에 요청을 처리할 수 있게 된다.
인증 방식으로 서버기반, 토큰기반으로 나뉘고 각각 어떤 특징을 가지는지 알게 되었으니 이제 JWT의 구조와 동작 방식에 대해서 자세하게 다뤄보자 🤤
JWT (Json Web Token) 란 위에서 언급했다 싶이 JSON 포맷의 Token을 의미한다.
JWT는 .
를 기준으로 세 부분으로 나눠지며 각각 Header, Payload, Signature를 의미한다.
Decoding 된 JWT는 아래와 같은 구조로 나타난다.
Header의 alg
는 정보를 암호화 할 해싱 알고리즘,typ
는 토큰의 타입을 지정한다.
Payload는 Token에 담겨질 정보를 가지고 있으며 key-value 형식으로 이루어진 한 쌍의 정보, Claim 이라고 한다.
Signature는 인코딩된 Header와 Payload를 더한 뒤 비밀키로 해싱하여 생성한다. Header와 Payload는 단순히 인코딩 된 값이기 때문에 제 3자가 복호화 할 수 있지만, Signature는 서버가 관리하는 비밀키가 유출되지 않는 한 복호화가 불가능 하다.
따라서 Signature는 토큰의 위변조 여부를 확인하는데 사용한다.
위와같은 장점에도 불구하고 Access Token이 제 3자에게 탈취당할 경우 보안에 취약하다.
보안을 강화하기 위해 Access Token의 유효기간을 줄이자니 그만큼 사용자가 로그인 요청을 자주 해서 새로운 Token을 발급 받아야 하므로 귀찮다. 하지만 이게 귀찮다고 유효기간을 늘리자니 보안에 취약하다는 굴레에 빠지게 된다..
이러한 굴레에 빠진 보안 걱정을 해결하기 위해 사용하는게 바로 Refresh Token이다.
Refresh Token을 적용한 JWT 인증과정은 아래와 같다.
앞의 과정은 Access Token과 Refresh Token을 같이 발급한다는 점만 제외하고는 위와 Access Token만을 사용할때와 동일하다.
Refresh Token은 처음 로그인에 성공했을 때, Access Token과 함께 발급된다.
하지만 Access Token과는 다르게 Refresh Token은 긴 유효기간을 가지면서 Access Token이 만료되었을 때 새로 발급해주는 역할을 하게 된다.
Access Token은 API 요청 시 마다 HTTP 통신을 통해 노출되지만 Refresh Token은 Access Token이 만료 되었을 때만 서버로 보내지기 때문에 탈취의 위험이 훨씬 적기 때문에 더 보안성이 높다는 장점이 있다.