인증(Authentication)
"당신이 누구인지" 확인하는 과정.
사용자가 본인이 맞는지 검증하는 단계로 로그인할 때 ID와 비밀번호를 입력하는것이 대표적이 예시
인가(Authorization)
"당신이 무엇을 할 수 있는지" 결정하는 과정.
인증된 사용자가 특정 리소스나 기능에 접근할 권한이 있는지 확인하는 단계
주요 인증 방식
1. 토큰 기반 인증 (JWT)
2. OAuth2.0 / 소셜로그인
3. 세션 기반 인증
이 중 첫번째인 토큰 기반 인증에 대해서 알아보자.
토큰 기반 인증이란?
서버가 로그인 성공 시 토큰을 발급하고, 이후 클라이언트가 이 토큰을 요청마다 전달하여 사용자를 인증하는 방식

- 토큰 인증 방법에는 다양한 방식이 있지만, 주로 OAuth 2.0 프로토콜에서 사용되는 Access Token(사용자의 인증과 권한을 나타내는 단기 유효 토큰(문자열))을 이용한다.
- Stateless 특성 : 서버가 세션상태를 유지하지 않는다. (유저의 정보가 서버에 저장되지 않음)
→ 서버는 매 요청마다 세션저장소를 조회할 필요가 없기 때문에 서버 확장성을 크게 향상 시킨다.
- 모바일 애플리케이션에 적합하다.
→ 모바일 네이티브 앱은 브라우저가 아니므로 쿠키를 자연스럽게 처리하기 어렵다.
JWT (JSON Web Token)


인증에 필요한 정보를 담고, 서명을 통해 위변조를 방지하는 JSON 기반 토큰. Access Token의 형식 중 하나.
Header
"토큰을 어떻게 검증하는가?" 에 대한 내용이 담겨 있다. (토큰 타입과 알고리즘 정보)
Payload
{
"sub": "1234567890",
"name": "John Doe",
"admin": true,
"iat": 1516239022
}
토큰에 대한 사용자 정보등의 데이터가 저장되어 있다.
→ 따라서 서버가 요청마다 데이터베이스에서 찾아야 할 것들이 줄어든다.
Signature
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secretKey
)
Header + Payload를 비밀키(서버만 알고있는 값)로 서명한 값. 토큰 위변조 여부를 검증한다.
최종적으로 이 세 부분은 Base64 Url로 인코딩되어 하나의 문자열로 결합되어 JWT 토큰을 구성하게 된다.
Access Token과 Refresh Token
Access Token의 역할은 말 그대로 API에 접근(access) 할 수 있는 권한 증명서 이다.
모든 API 요청에 포함되고 노출 빈도가 높으며, 보통 Authorization: Bearer 헤더로 전달된다.
즉, 가장 자주 사용되고, 가장 많이 노출되는 토큰이다.
Access Token 만을 사용했을때의 문제점은 다음과 같다.
1. 유효기간을 길게 주면 보안에 좋지 않다.
- 만료기간을 30일로 설정했고 토큰이 공격자에 의해 탈취된 상태라면 공격자는 만료 전까지 자유롭게 API 호출이 가능하다.
- JWT는 기본적으로 stateless 하므로 서버에서 즉시 토큰을 폐기하기도 어렵다.
2. 유효기간을 짧게 주면 UX가 무너진다.
- 만료기간이 5분이라면 5분마다 로그인이 필요
이 딜레마를 해결하기 위해 나온게 Refresh Token 이다.
Refresh Token은 새로운 Access Token을 재발급 받기 위해 사용되는 토큰이다.
Refresh Token의 존재 이유는 단 하나다. Access Token을 짧게 써도 되게 만들기 위해서다. (피해를 최소화 하기 위해)
일반적으로 Random String 방식을 사용한다. (Access Token은 JWT)
| 구분 | Access Token | Refresh Token |
| 목적 | API 인증 | 토큰 재발급 |
| 사용 빈도 | 매우 잦음 | 매우 낮음 |
| 수명 | 짧음 (분~수십분) | 김(일~월) |
| 탈취 시 피해 | 제한적 | 치명적 |
Access Token · Refresh Token을 함께 사용하는 구조는
“자주 쓰는 토큰은 짧게, 중요한 토큰은 최대한 숨긴다”는 보안 설계 철학에 기반한 방식이라고 볼 수 있다.
Access / Refresh Token의 저장 위치
탈취가 되지 않으려면 클라이언트에서는 이 토큰들을 어디에 저장해야할까?
1. Local Storage, SessionStorage => 권장 X
- LocalStorage는 브라우저를 닫아도 데이터가 유지되며 SessionStorage는 브라우저를 닫으면 데이터가 삭제된다.
- 두 저장소 모두 자바스크립트로 접근 가능하여 XSS 공격에 매우 취약하다.
2. 메모리 (Memory)
- JS의 private 변수, zustand등 전역 상태에 저장
- JS 런타임 종료시 자동 소멸(창 닫기 등), 새로고침시 초기화
- 새로고침을 자주 하지 않는 SPA(Single Page Application)에 적절
- 메모리 저장 방식 역시 XSS 공격 자체를 막아주지는 않지만, 브라우저 종료나 새로고침시 토큰이 사라지기 때문에 탈취 시 피해 범위를 시간적으로 제한할 수 있다.
3. HttpOnly 쿠키
- JS로 접근 불가하기 때문에 XSS 공격 방어 가능
- HTTPS에서만 전송
- 자동 전송으로 구현 단순
- SameSite=Strict 옵션으로 CSRF 공격 예방에도 도움이 된다.
Access Token은 메모리에 저장하는 것을 권장한다.
Access Token은 API 요청마다 사용되며 노출 빈도가 높고, 비교적 짧은 수명을 가지는 토큰이기 때문이다.
반면, Access Token을 HttpOnly 쿠키에 저장할 경우 브라우저가 요청마다 자동으로 토큰을 전송하게 되어, 프론트엔드에서 어떤 요청에 인증 정보를 포함할지 명확하게 제어하기 어렵다.
이는 자주 사용되고 짧게 유지되어야 하는 Access Token의 특성과 맞지 않으며, 결과적으로 인증 구조가 세션 기반 인증과 크게 다르지 않게 되는 문제가 있다.
Refresh Token은 HttpOnly 쿠키에 저장하는 것을 권장한다.
Refresh Token은 사용 빈도가 낮고 수명이 길며, 탈취될 경우 계정 전체가 장기간 노출될 수 있다.
HttpOnly 쿠키에 저장하면 자바스크립트로 접근할 수 없어 XSS로부터 보호할 수 있으며, 보다 안전하게 토큰을 관리할 수 있다.
RTR (Refresh Token Rotation)
RTR이란
Refresh Token을 한 번 사용할 때마다 새로 발급하고, 기존 Refresh Token은 즉시 무효화 하는 방식이다.
- Refresh Token은 1회용
- 재사용되면 침해로 간주
RTR이 없다면?
Refresh Token이 공격자에게 탈취되었을 경우, 공격자는 동일한 Refresh Token을 계속 재사용할 수 있다.
이때 서버는 해당 요청이 정상 사용자의 요청인지, 공격자의 요청인지 구분할 수 없다.
RTR이 해결하는 핵심은
“누가 진짜 사용자인지를 구분할 수 있게 해준다는 점”이다.
Refresh Token이 재사용되는 순간, 서버는 이를 명확한 침해 신호로 인식하고 모든 관련 세션을 즉시 무효화할 수 있다.
RTR의 보안 메커니즘을 그림으로 정리하면 다음과 같다.

한 줄 요약 : RTR은 Refresh Token의 재사용 여부를 통해 정상 사용자와 공격자를 구분할 수 있게 만드는 보안 장치다.
토큰 인증 방식의 전체 흐름 정리
마지막으로 토큰 인증 방식의 전체 흐름을 도식화해보면 다음과 같다.

출처
'지식' 카테고리의 다른 글
| [보안] XSS?, CSRF? - 웹 보안의 대표적인 두 가지 공격 이해하기 (0) | 2025.12.16 |
|---|