서버가 클라이언트 인증을 확인하는 방식 3가지:
- 쿠키 기반 인증
- 클라이언트의 브라우저에 정보를 저장하고, 서버와의 요청/응답 간에 클라이언트를 식별
- 서버는 쿠키를 통해 클라이언트를 식별하고 인증
- 세션 기반 인증
- 클라이언트의 인증 정보를 서버에 저장하고, 세션 ID를 통해 인증을 유지
- 클라이언트는 세션 ID를 쿠키에 담아 요청
- 토큰 기반 인증 (JWT)
- 서버는 클라이언트에게 인증 토큰을 발급하고, 클라이언트는 요청 시 토큰을 헤더에 담아 보냄
- 서버는 토큰을 통해 클라이언트 인증
1. 기존 인증 방식의 한계
- 쿠키 기반 인증의 문제점
- 쿠키에 민감 정보(id, pw)가 담기면 노출 위험
- 브라우저마다 쿠키 처리 방식이 달라 호환성 문제
- 쿠키가 클수록 네트워크 부하 증가
- 세션 인증의 문제점
- 세션 저장소 장애 시 전체 인증 무력화
→ 저장소에 문제가 생기면, 이미 로그인한 유저도 인증 불가 상태가 된다. - Stateful 구조로 확장성 떨어짐
→ HTTP는 원래 Stateless인데, 세션은 서버가 상태를 기억해야 하므로
→ 서버를 수평 확장(Scale-Out)하기 어려움 - 세션 저장소 운영 비용 발생
→ Redis나 DB 등을 세션 저장소로 사용해야 해서 추가 리소스와 비용이 든다 - 세션 ID 탈취 시 보안 위협
→ 세션 ID는 쿠키에 저장되기 때문에, 탈취당하면 공격자가 정상 사용자로 위장 가능. - 사용자 수 증가 = 메모리 사용 증가
→ 로그인 유저가 많아질수록 서버의 메모리 사용량이 계속 늘어난다. - 요청마다 세션 조회 필요
→ 클라이언트의 요청이 들어올 때마다 세션 저장소를 조회해야 해서,
→ 속도가 느려지고 서버 부하가 커질 수 있다
2. JWT란
JWT(Json Web Token)은 인증에 필요한 정보를 암호화 시킨 JSON 토큰으로 인터넷 표준 인증 방식
- 공개키와 개인키를 쌍으로 사용해서 토큰을 만들며,
- 토큰 안에는 위변조를 막기 위한 전자서명이 포함되어 보안성을 갖췄다.
- 별도의 세션 저장소 없이도 인증 정보를 유지할 수 있어서,
- 서버가 상태를 기억하지 않아도 되는 확장성 좋은 방식이다.
2-1 JWT 구조
: JWT는 각각의 구성요소가 점(.)으로 구분
xxxxx.yyyyy.zzzzz
Header.Payload.Signature
=> 전자서명 이 있어 위변조가 안된다!!
2-1-1 Header
: header에는 보통 토큰의 타입이나, 서명 생성에 사용할 해싱 알고리즘을 지정
{
"alg": "HS512",
"typ": "JWT"
}
- alg: 서명 알고리즘 (예: HS512)
- typ: 타입 (항상 JWT)
2-1-2 Payload
- 사용자 정보 or 토큰 정보를 담는 부분
- name-value 쌍으로 구성된 클레임(claim)들을 포함
클레임 종류
등록 클레임 (Registered) | 표준 이름 정의됨 | iss, sub, exp, iat |
공개 클레임 (Public) | URI 네임스페이스 필요 | https://example.com/user_id |
비공개 클레임 (Private) | 클라이언트와 서버 간 정의 | role, nickname 등 자유롭게 사용 |
JWT 는 공개 키이므로 decoding 하면 누구나 해당 정보를 알 수 있으므로
=> Payload 에 민감한 정보를 담지 않아야 한다!!!
등록된 (Registered) 클레임
- 등록된 클레임은 서비스 고유의 정보가 아니라, 토큰 자체에 대한 정보를 담기 위한 것이다.
- 이름이 이미 정해져 있으며, 사용은 필수가 아닌 선택사항이다.
- 대표적으로 아래와 같은 클레임들이 있다
iss | issuer | 토큰 발급자 |
sub | subject | 토큰 제목 |
aud | audience | 토큰 대상자 |
exp | expiration | 토큰 만료 시간 (항상 현재 시각 이후로 설정해야 한다) |
nbf | Not Before | 토큰 활성 시작 시간 (이전에는 사용 불가) |
iat | Issued At | 토큰 발급 시각 |
jti | JWT ID | 토큰의 고유 식별자 |
→ 이 클레임들은 JWT의 기본적인 정보를 정의하기 위한 표준으로 만들어짐
공개 (Public) 클레임
- 공개 클레임은 충돌을 방지하기 위해 고유한 이름을 가져야 한다.
- 그래서 보통 이름을 URI 형식으로 짓는 것이 일반적이다.
- 여러 시스템이 함께 쓰는 정보를 담을 때 사용하는 방식이다.
→ 이름이 겹치지 않도록 설계된, 범용적인 정보 전달을 위한 형식이다.
비공개 (Private) 클레임
- 비공개 클레임은 클라이언트와 서버 사이에서만 약속한 값들을 담는다.
- 이름 충돌의 위험이 있기 때문에 주의해서 사용해야 한다.
- 예를 들어 role, nickname 같은 서비스 특화 정보가 여기에 해당된다.
→ 서비스 내에서만 쓰는 커스텀 정보 교환용 방식이다.
2-1-3. Signature
HMACSHA512(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
- 위 Header + Payload를 서버의 비밀키로 서명
- 위조 방지 역할
- 오직 해당 서버만 이 토큰을 신뢰할 수 있음
3. JWT 장단점 정리
- JWT의 장점
Stateless 구조 | 세션 저장소 없이 인증 정보 유지 가능, 서버 부하 감소 |
확장성과 유연성 | 서버 상태를 저장하지 않기 때문에 분산 시스템이나 마이크로서비스에 적합 |
위변조 방지 | 토큰 자체에 전자서명(Signature)이 포함되어 있어 무결성 보장 |
빠른 인증 처리 | 서버에서 세션 조회 없이 토큰만 검증하면 되므로 처리 속도가 빠름 |
다양한 플랫폼 연동 | 모바일, 웹, 외부 API 등 다양한 환경에서 인증 토큰으로 활용 가능 |
싱글 사인온(SSO) 구현 용이 | 여러 서비스 간 인증 정보 공유에 적합 |
- JWT의 단점
민감 정보 노출 위험 | Payload는 단순 인코딩(Base64)만 되어 있어 노출 시 내부 정보 확인 가능 |
토큰 폐기 불가 | 발급된 토큰은 유효시간 내에는 강제로 폐기할 수 없음 |
탈취 시 위험 | 토큰이 유출되면 만료 전까지 악의적으로 사용될 수 있음 |
토큰 크기 증가 | Claim에 많은 정보를 담을수록 토큰 크기가 커져 네트워크 부담 초래 |
재사용 공격 가능성 | 별도 방어 로직이 없으면 동일한 토큰을 복제해서 재사용하는 공격 가능 |
보안 강화 작업 필요 | HTTPS, 토큰 암호화(JWE), Refresh Token 등 추가적인 보안 조치가 필요 |
- 단점 보완 방법
- 짧은 만료 시간 설정 (exp)
- Sliding Session: 사용 시마다 만료 시간 연장
- Refresh Token: Access Token 만료 시 새로운 토큰 발급
Access Token 이 만료되면 Refresh Token 으로 서버에게 새로운 Access Token 을 발급
Access Token은 짧게, Refresh Token은 길게 설정해서 보안을 유지
=> 만료 시간을 길게 주고 인증과는 전혀 상관없는 도구로 사용, 인증하고는 같이 쓰면 안됌
'백엔드의 이해' 카테고리의 다른 글
JWT 기반 인증 흐름 구현: 로그인, 로그아웃 및 토큰 관리 (0) | 2025.04.29 |
---|---|
Node.js 에 대하여 이해하기 (0) | 2025.03.31 |
SQL Mapper XML (1) | 2025.03.10 |