< JWT(Json Web Token) 이란? >
<목차>
Part.1 클라이언트 인증 방식 3가지
1. 쿠키 인증
2. 세션 인증
3. 토큰 인증
Part .2 JWT란?
1. JWT란?
2. JWT의 구조
3. Jwt를 이용한 인증 과정
4. 장단점
5. 왜 cookie 또는 session이 아닌 JWT를 사용할까?
6. JWT 사용시 주의사항
Part.1 클라이언트 인증 방식 3가지
JWT를 설명하기에 앞서 클라이언트 인증 방식 3가지에 대해 설명하고, 이를 바탕으로 왜 토큰 인증 방식을 사용하는지에 대해 설명하도록 하겠습니다. 서버가 클라이언트 인증을 확인하는 방식은 대표적으로 쿠키, 세션, 토큰 3가지 방식이 있습니다.
1. Cookie 인증
Cookie 인증이란?
Cookie는 Key-Value 형식의 문자열 입니다. 쿠키(Cookie)란 클라이언트가 어떠한 웹사이트를 방문할 경우, 그 사이트의 서버를 통해 클라이언트의 브라우저에 설치되는 작은 기록 파일입니다. 서버와 클라이언트가 대화하기 위한 수단이라고 생각하면 됩니다.
서버는 클라이언트의 로그인 요청에 대한 응답을 작성할 때, 클라이언트 측에 저장하고 싶은 정보를 응답 헤더의 Set-Cookie에 담습니다. 이후 해당 클라이언트는 요청을 보낼 때마다 매번 저장된 쿠키를 요청 헤더의 Cookie에 담아 보내면 서버는 쿠키에 담긴 정보를 바탕으로 해당 요청의 클라이언트가 누군지 식별할 수 있습니다. 각 사용자마다의 브라우저에 정보를 저장하여 고유 정보 식별이 가능합니다.
Cookie 인증 방식
1. 브라우저(클라이언트)가 서버에 요청(접속)을 보낸다.
2. 서버는 클라이언트 측에 저장하고 싶은 정보를 Response Header의 Set-Cookie에 담는다.
3. 이후 해당 클라이언트는 요청을 보낼 때마다, 저장된 쿠키를 Request Header의 Cookie에 담아 보낸다.
4. 서버는 Cookie에 담긴 정보를 바탕으로 해당 요청의 클라이언트가 누군지 식별 한다.
Cookie 방식의 단점
- 요청 시 쿠키의 값을 그대로 보내기 때문에 유출 및 조작의 위험이 존재합니다.
- 쿠키에 용량 제한이 있어 많은 정보를 담을 수 없습니다.
- 쿠키의 사이즈가 커질수록 네트워크 부하도 심해집니다.
- 웹 브라우저마다 쿠키 지원 형태가 달라 브라우저간 공유가 불가능합니다.
2. Session 인증
이러한 쿠키의 보안적인 이슈 때문에, 세션은 비밀번호 등 클라이언트의 민감한 인증 정보를 브라우저가 아닌 서버 측에 저장하고 관리합니다. 서버의 메모리에 저장하기도 하고, 서버의 로컬 파일이나 데이터베이스에 저장하기도 합니다.
유저가 웹사이트에서 로그인하면 세션이 서버 메모리(혹은 데이터베이스) 상에 저장됩니다.
이때, 세션을 식별하기 위한 Session Id를 기준으로 정보를 저장합니다.
세션 객체는 Key에 해당하는 SESSION ID와 이에 대응하는 Value로 구성되어 있습니다.
Value에는 세션 생성 시간, 마지막 접근 시간 및 User가 저장한 속성 등 이 Map 형태로 저장됩니다.
Session 인증 방식
1. 서버에서 브라우저에 쿠키에다가 Session Id를 저장한다.
2. 쿠키에 정보가 담겨있기 때문에 브라우저는 해당 사이트에 대한 모든 Request에 Session Id를 쿠키에 담아 전송한다.
3. 서버는 클라이언트가 보낸 Session Id 와 서버 메모리로 관리하고 있는 Session Id를 비교하여 인증을 수행한다.
Session 방식의 단점
- 외부에서 세션 ID 자체를 탈취하여 클라이언트인척 위장할 수 있습니다.
- 서버에서 세션 저장소를 사용하므로 요청이 많아지면 서버에 부하가 심해집니다.
- 클라이언트로부터 요청을 받으면 클라이언트의 상태를 계속에서 유지(Stateful)해놓고 사용하게되고, 이는 사용자가 증가함에 따라 성능의 문제를 일으킬 수 있으며 확장이 어렵다는 단점을 지닙니다.
3. Token 인증
이러한 단점을 극복하기 위해서 "토큰 기반 인증 시스템"이 나타났습니다.
토큰 기반 인증 시스템은 클라이언트가 서버에 인증을 요청하고 유효한 사용자일 경우 서버에서 해당 클라이언트에게 인증되었다는 의미로 '토큰'을 부여합니다.
이 토큰은 유일하며 토큰을 발급받은 클라이언트는 이후서버에 요청을 보낼 때 요청 헤더에 토큰을 담아 보냅니다.
그러면 서버에서는 클라이언트로부터 받은 토큰이 서버에서 제공한 토큰과 일치하는지 여부를 판단하여 인증 과정을 처리합니다.
이는 서버 기반 인증 시스템과 달리 클라이언트의 상태를 계속 유지하지 않으므로 Stateless 한 특징을 가지고 있습니다.
기존의 세션기반 인증은 서버가 파일이나 데이터베이스에 세션정보를 가지고 있어야 하고 이를 조회하는 과정이 필요하기 때문에 많은 오버헤드가 발생했습니다.
하지만 토큰은 세션과는 달리 서버가 아닌 클라이언트에 저장되기 때문에 메모리나 스토리지 등을 통해 세션을 관리했던 서버의 부담을 덜 수 있습니다.
왜냐하면 토큰 자체에 데이터가 들어있기 때문에 클라이언트에서 받은 토큰으로 서버에서는 위조되었는지 판별만 하면 되기 때문입니다.
토큰은 앱과 서버가 통신 및 인증할 때 가장 많이 사용되는데, 웹에는 쿠키와 세션이 있지만 앱에서는 없기 때문입니다.
Token 인증 방식
1. 사용자가 아이디와 비밀번호로 로그인을 한다.
2. 서버 측에서 클라이언트에게 access Token(유일성)을 발급한다.
3. 클라이언트는 서버 측에서 전달받은 토큰을 쿠키나 스토리지에 저장해 두고, 서버에 요청을 할 때마다 해당 토큰을 Request Header 에 담아 전달한다.
4. 서버는 전달받은 토큰을 검증하고 요청에 응답한다.
Token 방식의 단점
- 토큰 자체의 데이터 길이가 길어, 인증 요청이 많아질수록 네트워크 부하가 심해질수 있습니다.
- Payload 자체는 암호화되지 않기 때문에 유저의 중요한 정보는 담을 수 없습니다.
- 토큰을 탈취 당할 경우 대처가 어렵습니다.
Part .2 JWT (JSON Web Token)
1. JWT (JSON Web Token) 이란
JWT(JSON Web Token)란 인증에 필요한 정보들을 암호화시킨 JSON 토큰을 의미합니다. 주로 사용자의 인증(authentication) 또는 인가(authorization) 정보를 서버와 클라이언트 간에 안전하게 주고 받기 위해서 사용됩니다. JWT 기반 인증은 JWT 토큰(Access Token)을 HTTP 헤더에 실어 서버가 클라이언트를 식별하는 방식입니다. JWT는 JSON 데이터를 Base64 URL-safe Encode 를 통해 인코딩하여 직렬화한 것이며, 토큰 내부에는 위변조 방지를 위해 개인키를 통한 전자서명도 들어있습니다. 따라서 사용자가 JWT 를 서버로 전송하면 서버는 서명을 검증하는 과정을 거치게 되며 검증이 완료되면 요청한 응답을 돌려줍니다.
2. JWT 구조
JWT는 세 부분으로 구성됩니다.
- Header: 토큰의 유형과 해싱 알고리즘을 지정합니다.
- Payload: 클레임(claim) 정보라고 불리는 사용자의 인증/인가 정보(유저의 고유 ID값, 유효기간)를 포함하며, 이는 토큰에 담길 데이터입니다. 클레임은 등록된(registered), 공용(public), 비공개(private) 클레임으로 나뉘어집니다.
- Signature: 헤더와 페이로드를 기반으로 한 비밀키로 서명되어 저장, 토큰의 무결성을 검증하는 데 사용됩니다.
JWT 토큰은 네트워크로 전송되야 하기 때문에 공간을 적게 차지하는 것이 유리합니다.
따라서서 JSON 형식으로 데이터를 저장할 때 키(key)는 약어(3글자)를 사용합니다.
JWT에서 자주 사용되는 JSON 키 약어
- alg 키: 서명 알고리즘(algorithm)
- aud 키: 클라이언트(audience)
- exp 키: 만료 시각(expiration time)
- iat 키: 발급 시각(issued at)
- iss 키: 토큰 발급처
- sub 키: 인증 주체(subject)
- typ 키: 토큰의 유형(type)
3. JWT를 이용한 인증 과정
- 사용자가 ID, PW를 입력하여 서버에 로그인 인증을 요청한다.
- 서버에서 클라이언트로부터 인증 요청을 받으면, Header, PayLoad, Signature를 정의한다.
Hedaer, PayLoad, Signature를 각각 Base64로 한 번 더 암호화하여 JWT를 생성하고 이를 쿠키에 담아 클라이언트에게 발급한다. - 클라이언트는 서버로부터 받은 JWT를 로컬 스토리지(cookie 또는 다른 곳에 저장할 수 있다)에 저장한다.
API를 서버에 요청할때 Authorization header에 Access Token을 담아서 보낸다. - 서버는 클라이언트가 Header에 담아서 보낸 JWT가 내 서버에서 발행한 토큰인지 일치 여부를 확인한다.
인증이 되었을 경우, 페이로드에 들어있는 유저의 정보들을 select해서 클라이언트에 돌려준다.
4. JWT 장단점 정리
JWT 장점
- Header와 Payload를 가지고 Signature를 생성하므로 데이터 위변조를 막을 수 있습니다.
- JWT는 토큰에 대한 기본 정보와 전달할 정보 및 토큰이 검증됐음을 증명하는 서명 등 필요한 모든 정보를 자체적으로 지니고 있습니다.
- 클라이언트 측에서 토큰을 저장하고 유지 관리하므로 서버 측에서 세션을 관리할 필요가 없습니다.
- 클라이언트 인증 정보를 저장하는 세션과 다르게, 서버는 무상태(Stateless)가 되어 서버 확장성이 우수해질 수 있습니다.
- 간편한 구조와 전송이 가능한 형식이어서 다양한 플랫폼에서 사용 가능합니다.
- 토큰 기반으로 다른 로그인 시스템에 접근 및 권한 공유가 가능합니다. (쿠키와 차이)
- 모바일 어플리케이션 환경에서도 잘 동작한다. (모바일은 세션 사용 불가능하기 때문)
- 클레임을 통해 추가 데이터를 포함할 수 있어 유연한 데이터 교환 가능합니다.
서버 무상태(Stateless)
서버가 클라이언트의 상태를 보존하지 않는다는 것을 의미하며 계속 상태를 보존할 수록 부하가 커지기때문에 서버 확장성에 영향을 준다.
JWT 단점
- 토큰 자체에 정보를 담고 있으므로 정보 노출의 위험이 있습니다.
- 토큰의 Payload에 3종류의 클레임을 저장하기 때문에, 정보가 많아질수록 토큰의 길이가 늘어나 네트워크에 부하를 줄 수 있습니다.
- payload 자체는 암호화 된 것이 아니라 BASE64로 인코딩 된 것이기 때문에, 중간에 Payload를 탈취하여 디코딩하면 데이터를 볼 수 있으므로, payload에 중요 데이터를 넣어서는 안됩니다.
- 토큰을 클라이언트 측에서 관리하고 저장하기 때문에 토큰 자체를 탈취당하면 대처하기가 어렵습니다.
5. 왜 cookie 또는 session이 아닌 JWT를 사용할까?
서버에서 가장 피해야 할 것은 데이터베이스 조회입니다. 이런 점에서, JWT 토큰은 DB조회를 안해도 되는 장점을 가지고 있습니다.
JWT는 토큰 자체에 사용자의 정보가 저장되어 있어있기 때문에 서버 입장에서 토큰을 검증만 해주면 됩니다. 반면에 쿠키와 세션을 사용할 때는 서버 단에 로그인한 모든 사용자의 세션을 DB나 캐시(cache)에 저장해놓고 쿠키로 넘어온 세션 ID로 사용자 데이터를 매번 조회해야합니다. 따라서 JWT를 사용할 때는 사용자가 늘어나더라도 사용자 인증을 위해서 추가로 투자해야하는 인프라 비용을 크게 절감할 수 있습니다. 이러한 측면에서 확장성에 용이하기 때문에 현업에서는 JWT를 활발하게 사용하고 있습니다.
토큰 인증이 신뢰성을 가지는 이유
JWT는 Base64로 암호화를 하기 때문에 디버거를 사용해서 인코딩된 JWT를 1초만에 복호화할 수 있습니다.
복호화 하면 사용자의 데이터를 담은 Payload 부분이 그대로 노출됩니다.
따라서 페이로드에는 비밀번호와 같은 민감한 정보는 넣어서는 안됩니다.
그럼 토큰 인증 방식이 안전하지 않은걸까요?
토큰의 진짜 목적은 정보 보호가 아닌, 위조 방지입니다.
아래와 같이 시그니처에 사용된 비밀키가 노출되지 않는 이상 데이터를 위조해도 시그니처 부분에서 위조 여부가 걸러지기 때문입니다.
유저 JWT: A(Header) + B(Payload) + C(Signature) 일 때 (만일 임의의 유저가 B를 수정했다고 하면 B'로 표시한다.)
- 다른 유저가 B를 임의로 수정 -> 유저 JWT: A + B' + C
- 수정한 토큰을 서버에 요청을 보내면 서버는 유효성 검사 시행
- 유저 JWT: A + B' + C
- 서버에서 검증 후 생성한 JWT: A + B' + C' => (signature) 불일치
- 대조 결과가 일치하지 않아 유저의 정보가 임의로 조작되었음을 알 수 있습니다.
다시 말해, 토큰은 페이로드의 정보가 노출되거나 임의로 변경되어도 시그니처를 이용해 위조 여부를 가려내어 임의의 유저가 서버에 접근하는 것을 막아줍니다.
6. JWT 사용 시 주의 사항
- 토큰이 한 번 발급되면 변경이 불가능하므로 중요한 정보를 담아야 합니다.
- JWT 토큰 서버에서만 유효성을 검증할 수 있지만 그 안에 저장된 데이터는 누구나 쉽게 열람이 가능하므로 보안에 신경 써야 합니다.
- 서명(Signature)이 사용되므로 암호화는 되지 않으며, 중요한 데이터의 경우 별도의 암호화가 필요할 수 있습니다.
- 가급적 JWT 토큰에는 사용자를 식별할 수 있는 아이디 정도만 저장하는 것이 좋으며 해당 사용자에 대한 추가 정보가 필요한 경우에는 서버에서 사용자 DB를 조회하는 것이 안전합니다.
참고 문서
http://www.opennaru.com/opennaru-blog/jwt-json-web-token/
'Web Development > Front End 관련 개념 정리' 카테고리의 다른 글
Local Storage & Session Storage란? (0) | 2023.08.16 |
---|---|
webpack이란? (0) | 2023.08.16 |
[OAuth2.0] OAuth 2.0이란? (0) | 2023.08.15 |
[ OAuth 2.0 ] Access Token & Refresh Token 으로 보안 강화하기 (0) | 2023.08.14 |
git & github 사용하기 (0) | 2023.04.12 |