쿠키
- 쿠키 이름의 유래, 역사적 배경(매직 쿠키) 이해
- 쿠키의 구조, 범위, 생명주기, 브라우저 동작 방식
- HttpOnly, Secure, SameSite, Domain, Path, Max-Age/Expires 등 속성의 의미, 조합
쿠키(Cookie)
브라우저가 보관하고 요청마다 자동 전송하는 작은 데이터(세션 기반)
서버는 쿠키를 활용해 무상태(Stateless)인 HTTP에서 사용자의 상태(로그인 여부 등)를 복원함
1) 이름이 왜 쿠키임?
- 매직 쿠키(Magic Cookie)
초기 유닉스와 네트워크 프로그래밍에서 사용하던 용어임. 프로그램간에 주고받는 해석하지 않는 불투명한 토큰을 의미함
- 넷스케이프 시절 웹 애플리케이션에서 상태 유지를 위해 이 개념을 사용했고, 사용자에게 전해지는 작은 토큰이라는 의미에서
쿠키라는 이름을 썼음
- 포츈 쿠키를 비유하는데, 겉으로는 작은 과자이지만 안에 작은 쪽지(토큰)가 들어있어, 열어보는 사람에게 정보를 전달함.
* 쿠키는 서버가 부여한다. 브라우저는 이름과 값을 보관하고 전송할 뿐, 내용은 해석하지 않는다.
2) 쿠키의 구조와 속성
기본 형태 : Name = Value
속성은 세미콜론으로 구분된 Key=Value 또는 플래그라고 함
Set-Cookie: SESSIONID=abc123;
Path=/;
Domain=example.com;
Max-Age=1800;
HttpOnly; Secure;
SameSite=Lax
| Name=Value | 쿠키의 이름과 값을 의미함 | 값에는 공백, 세미콜론 등 특수문자 금지 필요 시 URL 인코딩이 권장됨 |
| Domain | 쿠키가 전송될 도메인의 범위 | 미설정시 호스트 전용이 됨 설정시 해당 도메인 및 하위 도메인에 전송 |
| Path | 전송 경로를 제한함 | 접두 경로(prefix) 매칭, 보통 / 를 권장함 |
| Expires | 만료시각(절대시각) | 표준화된 GMT 날짜 문자열 |
| Max-Age | 만료까지 남은 시간(초) | Max-Age는 Expires보다 우선한다 |
| Secure | HTTPS 연결에서만 전송됨 | 민감한 쿠키의 경우에는 필수임 |
| HttpOnly | JS의 접근을 차단함 | XSS를 완화. 인증 쿠키에 강력하게 권장 |
| SameSite | 크로스 사이트 전송 제어 | Lax가 기본. SSO나 외부 리다렉션은 None + Secure 필요 |
| Priority(브라우저별) | 제거 우선순위 힌트?를 의미함 | 용량 초과시 폐기 우선순위에 영향? |
쿠키 이름 접두사
| 접두사 | 요구조건 | 효과 |
| __Secure- | Secure 필수 | 보안 전용임을 표현하는 관례라고 함 |
| __Host- | Secure 필수, Path=/ ,Domain 금지 | 호스트 고정, 하위 도메인 오남용 차단에 유용함 |
3) 브라우저의 쿠키 처리 흐름
- 도메인/경로 매칭에 부합하는 요청에만 자동으로 전송됨
- 동일 이름의 쿠키가 경로나 도메인에 따라 여러개 존재할 수 있음(브라우저 구현차가 있기 때문에 혼동 피하기)
4) 생명주기와 용량 제한
- 세션 쿠키 : Expires / Max-Age 미지정함. 브라우저가 종료되면 삭제됨
- 영속 쿠키 : 만료 정보를 지정함(Expires, Max-Age). 지정된 시간까지 쿠키가 유지됨
- 용량 : 브라우저마다 다르나 쿠키 하나에 약 4KB정도 한다고 함, 도메인당 수십개 수준이 일반적이다
초과시 오래된 쿠키부터 삭제될 수 있다.
5) 도메인과 경로 매칭 규칙
- Domain 미설정 : 호스트 전용 쿠키임. 정확히 일치하는 호스트에서만 전송함
- Domain=example.com 설정 : sub.example.com 을 포함하는 하위 도메인에도 전송함
- Path=/account: /account와 그 하위 경로에만 전송함
* 인증 쿠키는 호스트 전용 + Path=/ + __Host- 접두사로 범위를 최소하하는걸 권장한다고 함!
6) 디렉토리 구조 예시
src/main/java/auth/
CookieUtil.java - > 쿠키 파서/ 빌더
SessionStore.java - > In-memory 또는 Redis 인터페이스
CsrfProtector.java - > CSRF 토큰 발급/검증
AuthController.java - > 로그인/로그아웃, 보호 리소스 예시
7) 예제 : 쿠키 세팅, 파싱
// 쿠키 설정 예시
String sessionId = UUID.randomUUID().toString();
String cookie = "SESSION=" + sessionId
+ "; Path=/"
+ "; HttpOnly"
+ "; Secure"
+ "; SameSite=Lax"
+ "j Max-Age=1800";
response.addHeader("Set-Cookie", cookie); // 인증 세션 쿠키 발급
// 요청에서 쿠키 읽기
String cookieHeader = request.getHeader("Cookie"); // 요청에서 헤더 얻고
Map<String, String> jar = CookieUtil.parse(cookieHeader); // 쿠키헤더를 파싱? 한다음
String session = jar.get("SESSION"); // 세션을 얻음
// 파서 예시
class CookieUtil {
static Map<String, String> parse(String header) {
Map<String, String> map = new HashMap<>();
if(header == null) {
return map;
} // if 끈
for(String pair : header.split(";") {
String[] kv = pair.trim().split("=",2);
if(kv.length==2) {
map.put(kv[0],kv[1]);
} // if 끝
} // for 끝
return map;
}
}
* 인증 정보는 절대 쿠키값에 직접 담지 않고, 세션ID 또는 서명된 토큰만 저장함
* 민감한 정보가 담긴 쿠키에는 HttpOnly + Secure + SameSite를 기본적으로 적용하기
* 도메인 전역 쿠키는 남발하지 않기. 최소 범위의 원칙을 꼭 지키기
'Spring Boot' 카테고리의 다른 글
| 쿠키와 세션 기반 인증 : 쿠키와 세션 보안 설정 (0) | 2025.09.24 |
|---|---|
| 쿠키와 세션 기반 인증 : 세션 기반 인증 (0) | 2025.09.24 |
| 유저 관리 기능 : 인증 워크플로우 (0) | 2025.09.24 |
| 유저 관리 기능 : 유저 기능의 필요성과 활용 (0) | 2025.09.23 |
| 로깅 : 로그 분석과 활용 (1) | 2025.08.21 |