본문 바로가기

Spring Boot

쿠키와 세션 기반 인증 : 쿠키의 개념, 특성

쿠키

 

 - 쿠키 이름의 유래, 역사적 배경(매직 쿠키) 이해

 - 쿠키의 구조, 범위, 생명주기, 브라우저 동작 방식

 - 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를 기본적으로 적용하기

* 도메인 전역 쿠키는 남발하지 않기. 최소 범위의 원칙을 꼭 지키기