2025. 1. 21. 11:12ㆍCS
1. 들어가며
웹 인증이란 무엇인가?
웹 인증은 사용자가 누구인지 식별하고, 그 사용자에게 적절한 접근 권한을 부여하는 과정을 의미한다.
이 과정은 보안의 핵심으로, 사용자가 웹 애플리케이션에 로그인하거나 특정 리소스에 접근할 때 반드시 필요하다.
웹 인증의 기본 흐름
1. 사용자가 자신의 정보를 입력하여 서버에 인증 요청을 보낸다.(ex: ID, 비밀번호)
2. 서버는 이 정보를 확인하여 사용자가 신뢰할 수 있는 대상인지 판단한다.
3. 인증이 완료되면, 서버는 이후 요청을 처리하기 위해 인증 상태를 유지하는 메커니즘을 제공한다.
여기서 인증 상태를 유지하는 다양한 방법으로 쿠키, 세션, 토큰이 사용된다.
특히 JWT와 같은 토큰 기반 인증 방식이 주목을 받고 있다.
쿠키, 세션, 토큰, JWT를 다루는 이유
웹 인증을 구현하는 데는 다양한 방식이 있다.
각 방식은 고유한 특징과 사용 목적을 가지며, 적절히 선택하여 사용하는 것이 중요하다.
1. 쿠키
- 클라이언트 측에서 인증 정보를 저장하여 상태를 유지한다.
- 브라우저 중심의 인증 방식에 자주 사용된다.
2. 세션
- 서버 측에서 인증 정보를 관리하며, 쿠키와 함께 사용된다.
- 사용자의 상태를 서버에서 직접 추적하는 데 효과적이다.
3. 토큰
- 인증 정보를 캡슐화하여 클라이언트와 서버 간에 교환한다.
- 모바일 및 SPA(Single Page Application) 환경에서 많이 사용된다.
4. JWT(Json Web Token)
- JSON 형식으로 인증 정보를 담아 서명한 토큰이다.
- 서버가 상태를 저장하지 않아도 인증을 처리할 수 있는 Stateless 인증 방식을 제공한다.
SPA 환경에서 토큰이 많이 사용되는 이유
1. Stateless 인증
: 토큰 기반 인증은 서버에 상태(Session)을 저장하지 않으므로 서버 확장이 쉽고, API 서버 간에 인증 상태를 공유하기 편리하다.
2. CORS 문제 해결
토큰은 헤더에 담아 전송되므로, 쿠키 기반 인증처럼 CORS(Cross-Origin Resouce Sharing) 설정에서 복잡한 제약을 덜 받는다.
3. 프론트엔드와 백엔드 분리
SPA는 보통 프론트엔드와 백엔드가 분리되어 동작하므로, 토큰을 사용하면 인증 정보를 REST API나 GraphQL API와 쉽게 교환할 수 있다.
4. 다양한 클라이언트 지원
토큰은 브라우저뿐 아니라 모바일 앱, 데스크톱 앱 등 다양한 클라이언트에서 동일하게 사용할 수 있다.
5. JWT의 간편함
JWT는 인증 정보와 함께 권한 정보 등을 포함할 수 있고, 서버에서 별도의 상태 저장 없이 토큰 자체로 인증을 처리할 수 있다.
2. 쿠키(Cookie)
쿠키의 정의와 특징
쿠키(Cookie)는 클라이언트(브라우저) 측에 저장되는 작은 데이터 파일로, 사용자의 상태 정보를 저장하여 서버와 클라이언트 간의 연결을 유지하거나 사용자 경험을 개인화하는 데 사용된다.
특징
- 클라이언트에 저장되며, 브라우저와 함께 동작한다.
- HTTP 요청 시 자동으로 서버로 전송된다.
- 데이터 크기 제한: 약 4KB 정도로 비교적 적은 양의 데이터만 저장 가능하다.
- 보안 설정 가능: HttpOnly, Secure 속성으로 보안을 강화할 수 있다.
쿠키의 구조와 동작 방식
쿠키의 기본 구조

- 이름(name): 쿠키의 키
- 값(value): 저장된 데이터
- 만료 시간(expires): 쿠키의 유효 기간
- 도메인(domain): 쿠키가 전송될 도메인
- 경로(path): 쿠키가 유효한 URL 경로
- 보안 속성(secure, HttpOnly): 보안 설정을 위한 옵션
쿠키의 동작 방식
1. 서버가 쿠키를 설정
: 사용자가 서버에 요청을 보내면 서버가 Set-Cookie 헤더를 포함해 응답을 보낸다.
2. 클라이언트에 쿠키 저장
: 브라우저는 쿠키를 저장하고, 만료 기간 동안 유지한다.
3. 쿠키 전송
: 이후 클라이언트가 동일한 도메인에 요청을 보낼 때 저장된 쿠키가 자동으로 요청 헤더에 포함된다.
예시
HTTP/1.1 200 OK
Set-Cookie: sessionId=abc123; Expires=Tue, 20 Jan 2025 12:00:00 GMT; HttpOnly; Secure
=> 클라이언트는 sessionId=abc123 쿠키를 저장하고, 이후 서버로 요청 시 함께 전송된다.
쿠키의 장단점
장점
1. 클라이언트 상태 저장
: 서버가 상태를 유지할 필요 없이 클라이언트에서 정보를 관리한다.
2. 사용자 경험 개인화
: 사용자 설정(예: 다크 모드, 언어 선택)과 같은 정보를 저장하여 개인화된 경험 제공
3. 간편한 구현
: 서버에서 쿠키를 설정하고 클라이언트가 이를 자동으로 전송하므로 구현이 간단하다.
단점
1. 보안 문제
: 쿠키가 클라이언트에 저장되므로, XSS(Cross-Site Scripting) 및 CSRF(Cross-Site Request Forgery) 공격에 취약하다.
2. 데이터 크기 제한
: 약 4KB로 저장 가능한 데이터 크기가 작아 대량의 데이터를 저장하기 어렵다.
3. CORS 문제
: 다른 도메인으로 요청 시 CORS 정책으로 인해 쿠키를 전송하려면 추가 설정이 필요하다.
4. 브라우저 의존성
: 쿠키는 브라우저 중심으로 동작하므로 비브라우저 환경에서는 사용할 수 없다.
3. 세션(Session)
세션의 정의와 특징
세션(Session)은 서버 측에서 사용자의 상태를 관리하기 위해 생성되는 저장 공간이다.
사용자가 웹 애플리케이션에 접속하면 서버는 고유한 세션 ID를 생성하고, 이를 통해 사용자의 상태를 식별하고 유지한다.
특징
- 서버에 데이터를 저장하므로 클라이언트 측에서 정보를 직접 보지 못한다.
- 세션 ID는 보통 쿠키를 통해 클라이언트로 전달된다.
- 클라이언트가 브라우저를 닫거나 서버의 세션 만료 시간이 지나면 세션이 종료된다.
- 보안이 상대적으로 뛰어나지만, 서버 자원을 소모한다.
세션의 구조와 동작 방식
구조
- 세선 저장소: 서버가 세션 데이터를 저장하는 공간(메모리, 데이터베이스 등)
- 세션 ID: 클라이언트와 서버 간 세션을 식별하기 위한 고유 값
- 클라이언트: 세션 ID를 포함한 요청을 서버로 전송한다.
동작 방식
1. 클라이언트의 요청
: 사용자가 서버에 처음 요청을 보낸다.
2. 세션 생성
: 서버는 새로운 세션 ID를 생성하고, 이를 클라이언트의 쿠키에 저장하여 응답한다.
3. 세션 사용
- 클라이언트는 이후 요청 시 세션 ID를 쿠키에 포함해 전송한다.
- 서버는 세션 ID를 확인하고, 관련 데이터를 저장한다.
4. 세션 종료
: 브라우저 종료 또는 세션 만료 시간 이후, 세션이 종료된다.
예시(Servlet에서 세션 사용)
HttpSession session = request.getSession(); // 세션 가져오기
session.setAttribute("username", "JohnDoe"); // 세션에 데이터 저장
String username = (String) session.getAttribute("username"); // 세션 데이터 읽기
session.invalidate(); 세션 종료
세션과 쿠키의 차이
구분 | 세션(Session) | 쿠키(Cookie) |
저장 위치 | 서버 | 클라이언트(브라우저) |
보안 | 보안에 강함(데이터가 서버에 저장됨) | 보안에 약함(클라이언트에 데이터 노출) |
속도 | 서버 자원을 소모하므로 느릴 수 있음 | 클라이언트에서 처리되므로 상대적으로 빠름 |
유효 기간 | 브라우저 종료 또는 설정된 만료 시간까지 | 만료 시간을 설정하지 않으며 브라우저 종료 시 삭제 |
사용 용도 | 사용자 인증 및 민감한 데이터 관리 | 비민감한 데이터 저장 및 상태 유지 |
예시 비교
1. 세션
- 로그인 상태 유지(사용자 인증 정보를 서버에서 관리)
- 서버가 로그인된 사용자 정보를 확인하고 처리
2. 쿠키
- 다크 모드 여부 저장
- 클라이언트에서 개인화된 설정 정보를 유지
4. 토큰(Token)
토큰의 개념과 종류
토큰(Token)은 인증 및 권한 부여를 위해 서버와 클라이언트 간에 교환되는 데이터 조각이다.
토큰은 특정 작업을 수행하거나 리소스에 접근할 권한을 나타낸다.
종류
1. Bearer Token
- 요청 헤어데 포함하여 인증
- OAuth2에서 자주 사용
- 예: Authorization: Bearer <token>
2. Refresh Token
- 액세스 토큰이 만료된 경우 새 토큰을 발급받기 위한 용도
- 보통 저장소에 안전하게 보관
3. JWT(JSON Web Token)
- JSON 형식으로 데이터를 담고, 서명을 통해 무결성을 보장
- 토큰 자체에 사용자 정보를 포함하여 서버가 별도의 상태를 저장하지 않아도 됨
4. Opaque Token
- 토큰 자체는 읽을 수 없는 형태
- 서버가 토큰을 저장하고 검증
토큰의 구조와 동작 방식
토큰의 기본 구조
- 토큰은 보통 문자열로 이루어져 있으며, 고유 식별자(ID)나 암호화된 데이터로 구성된다.
- JWT의 경우, 구조는 다음과 같다.
1. Header: 토큰 타입(JWT)과 알고리름 정보
2. Payload: 사용자 정보와 클레임(권한, 만료 시간 등)
3. Signature: 무결성을 확인하기 위한 서명
JWT 예시
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IkpvaG5Eb2UiLCJleHAiOjE2ODQxODg4MDB9.abc123signature
동작 방식
1. 사용자 인증 요청
: 사용자가 서버에 인증 정보를 보낸다.(예: ID와 비밀번호)
2. 토큰 발급
: 서버는 사용자 정보를 검증 후, 토큰을 발급한다.
3. 토큰 저장
: 클라이언트는 토큰을 저장(예: 브라우저 localStorage 또는 sessionStorage)한다.
4. 토큰 사용
- 클라이언트는 요청 시 토큰을 포함하여 서버로 보낸다.(예: HTTP 헤더)
- 서버는 토큰을 검증하고 요청을 처리한다.
5. 토큰 갱신
: 액세스 토큰이 만료되면, Refresh Token을 통해 새 토큰을 발급받는다.
토큰 기반 인증의 장단점
장점
1. Stateless
- 서버에서 상태(Session)을 저장하지 않아도 인증 가능
- 수평 확장이 용이
2. 유연성
: 웹, 모바일, 데스크톱 등 다양한 클라이언트에서 사용 가능
3. 효율성
: 토큰 자체에 정보가 포함되어 추가 요청 없이 인증 처리
4. 보안 강화
: 서명(Signature)을 통해 데이터의 무결성 검증
단점
1. 토큰 탈취 위험
: 탈취된 토큰은 만료 전까지 재사용 가능(Bearer Token의 한계)
2. 갱신 및 만료 관리
: 액세스 토큰과 리프레시 토큰의 만료 정책을 적절히 관리해야 함
3. 토큰 크기
: JWT는 구조적 데이터(JSON)를 포함하므로 크기가 커질 수 있음
4. 보안 설정 필요
: HTTPS와 적절한 저장 방식(HttpOnly, Secure)이 필수
예시
Bearer Token 사용
GET /user-profile HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
JWT 검증 로직(Java)
import io.jsonwebtoken.Jwts;
String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...";
String secretKey = "mySecretKey";
try {
Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(token); // 토큰 검증
System.out.println("Token is valid");
} catch (Exception e) {
System.out.println("Invalid token");
}
5. JWT(JSON Web Token)
JWT의 정의와 특징
JWT(JSON Web Token)는 JSON 형식으로 데이터를 저장하고, 서명을 통해 무결성을 보장하는 토큰 기반 인증 방식이다.
서버에서 상태(Session)를 저장하지 않고도 클라이언트를 인증할 수 있는 Stateless 인증 방식을 제공한다.
특징
- Self-contained: 토큰 자체에 인증 정보와 권한 정보가 포함되어 별도의 서버 요청 없이 인증을 처리할 수 있다.
- Base64 URL-encoded: JWT는 URL-safe한 형식으로 인코딩되어 쉽게 전달할 수 있다.
- 서명(Signature): 데이터를 암호화하지는 않지만, 서명을 통해 데이터 변조를 방지한다.
- Stateless: 서버가 클라이언트의 상태를 저장하지 않아 수평 확장이 용이하다.
JWT의 구조 (Header, Payload, Signature)
JWT는 세 부분으로 구성된다.
1. Header
- 토큰의 유형(JWT)과 서명 알고리즘을 정의한다.
- 예시:
{
"alg": "HS256",
"typ": "JWT"
}
2. Payload
- 사용자 정보와 클레임(Claim)을 포함하는 데이터 부분이다.
- 클레임 유형
- Registered claims: 표준 클레임(iss, sub, exp 등)
- Public claims: 공개 클레임(사용자 정의 가능)
- Private claims: 클라이언트-서버 간에 정의된 클레임
- 예시:
{
"sub": "1234567890",
"name": "John Doe",
"admin": true,
"exp": 1684188800
}
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
JWT 예시:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
.
s5iSwA9fzE-TbTtQazENB2-32-Z6WYW_wmITgU0Qs5I
JWT의 동작 방식(발급, 검증 과정)
발급 과정
1. 클라이언트가 사용자 인증 정보를 서버에 전송한다. (예: ID, 비밀번호)
2. 서버는 사용자 정보를 검증한 뒤, JWT를 생성하여 클라이언트에 반환한다.
3. 클라이언트는 JWT를 저장(예: localStorage, sessionStorage)하고 이후 요청에 포함한다.
검증 과정
1. 클라이언트가 요청 시 JWT를 HTTP 헤더(Authorization: Bearer <JWT>에 포함)로 서버에 전달한다.
2. 서버는
- JWT의 서명을 검증하여 무결성을 확인한다.
- Payload의 만료 시간(exp) 및 클레임을 확인한다.
3. 검증이 성공하면 요청을 처리하고, 실패하면 인증 오류를 반환합니다.
JWT의 장단점
장점
1. Stateless
: 서버에 상태를 저장하지 않아 확장이 쉽다.
2. Self-contained
: 사용자 정보와 권한이 토큰에 포함되어 추가 요청 없이 인증이 가능하다.
3. 다양한 환경 지원
: 웹, 모바일, 데스크톱 등 다양한 클라이언트에서 사용할 수 있다.
4. 효율적인 인증
: 서버-클라이언트 간 인증 요청을 줄여준다.
단점
1. 탈취 위험
- JWT가 탈취되면 만료 전까지 악용될 수 있다.
- 해결책: HTTP 사용 및 만료 시간 짧게 설정
2. 크기 문제
- JWT는 Base64로 인코딩된 JSON 데이터로 크기가 크다.
- 헤더에 추가적인 데이터 사용 시 네트워크 비용 증가
3. 무효화 어려움
- 발급된 JWT는 만료되기 전까지 철회(revoke)가 어렵다.
- 해결책: 서버에서 블랙리스트 또는 짧은 만료 시간과 Refresh Token 사용
4. 정보 노출
- JWT는 암호회되지 않으므로(Base64 인코딩) Payload에 민감한 정보를 저장하면 안된다.
예시:
JWT 발급
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
String secretKey = "mySecretKey";
String jwt = Jwts.builder()
.setSubject("1234567890")
.claim("name", "John Doe")
.claim("admin", true)
.signWith(SignatureAlgorithm.HS256, secretKey)
.compact();
System.out.println("Generated JWT: " + jwt);
JWT 검증
import io.jsonwebtoken.Jwts;
String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...";
try {
Jwts.parser()
.setSigningKey("mySecretKey")
.parseClaimsJws(token);
System.out.println("Token is valid");
} catch (Exception e) {
System.out.println("Invalid token");
}
쿠키, 세션, 토큰, JWT 비교
인증 방식별 차이점
구분 | 쿠키(Cookie) | 세션(Session) | 토큰(Token) | JWT(JSON Web Token) |
저장 위치 | 클라이언트(브라우저) | 서버 | 클라이언트 또는 헤더로 전송 | 클라이언트 또는 헤더로 전송 |
상태 관리 | 클라이언트에서 상태 유리 | 서버에서 상태 관리 | Stateless 또는 Stateful | Stateless |
보안 | 클라이언트에 저장되므로 보안 약간 | 서버에서 민감 정보 관리, 상대적으로 안전 | 토큰 탈취 시 재사용 가능 | 서명으로 무결성 보장, 민감 정보는 저장 금지 |
유효 기간 | 만료 시간 설정 필요 | 서버 설정에 따름 | 토큰 자체 만료 시간 설정 가능 | 토큰 자체 만료 시간 포함 |
확장성 | 제한적(Stateful) | 제한적(서버에 상태 저장) | 클라이언트 중심으로 확장 용이 | 클라이언트 중심으로 확장 용이 |
사용 용도 | 사용자 설정 저장, 비민감 정보 | 로그인 상태 유지, 민감 정보 관리 | API 인증, 다양한 플랫폼에서 사용 | API 인증, 다양한 플랫폼에서 사용 |
유효성 검증 | 요청 시 자동 전송 | 세션 ID로 서버에서 데이터 확인 | 서버가 토큰을 확인 | 토큰 자체에 서명 포함, 서버 검증 간소화 |
각 방식의 적합한 사용 사례
1. 쿠키(Cookie)
- 적합한 사례
- 비민감 데이터 저장: 다크 모드, 언어 설정 등 사용자 설정
- 간단한 상태 유지: 사용자의 이전 작업 정보 저장(예: 장바구니)
- 브라우저 기반 인증: 간단한 로그인 상태 유지
- 예시
- 쇼핑몰에서 장바구니 정보를 유지하는 데 사용
2. 세션(Session)
- 적합한 사례
- 민감한 데이터 관리: 로그인 상태, 사용자 인증 정보
- 웹 애플리케이션: 서버에서 사용자의 상태를 관리해야 할 때
- 예시
- 사용자가 로그인한 뒤, 서버에서 개인 데이터를 처리하는 서비스(예: 인터넷 뱅킹)
3. 토큰(Token)
- 적합한 사례
- API 인증: RESTful API나 GraphQL API 호출 시
- 분산 시스템: 여러 서버에서 인증 상태를 공유해야 할 때
- 모바일 앱 및 SPA: 클라이언트 중심 애플리케이션에서 상태 유지
- 예시
- 모바일 앱에서 API 요청 시 Bearer 토큰 사용
4. JWT(JSON Web Token)
- 적합한 사례
- Stateless 인증: 서버에서 상태를 저장하지 않아야 할 때
- 다양한 플랫폼 지원: 웹, 모바일, 데스크톱 등 다양한 환경
- 권한 관리: 사용자 역할과 권한을 토큰에 포함하여 관리
- 예시
- 클라이언트가 로그인 후 JWT를 사용해 REST API 호출 및 인증
'CS' 카테고리의 다른 글
[알고리즘] 백트래킹(Backtracking) (0) | 2025.01.04 |
---|---|
[자료구조] List Map Set의 차이와 활용(Java) (0) | 2025.01.03 |
[알고리즘] 백트래킹(Backtracking) (1) | 2024.12.28 |
[알고리즘] 동적 계획법(Dynamic Programming, DP) (0) | 2024.12.28 |
[알고리즘] BFS(너비 우선 탐색)와 DFS(깊이 우선 탐색) (0) | 2024.12.21 |