즉, HTTP 프로토콜은 기본적으로 무상태성을 가지고 있기 때문에
서버와 클라이언트 간의 연결 유지를 구현하기 위해 서로를 인식할 수 있는 식별데이터가 필요했고, 그것이 쿠키 데이터 조각이라고 볼 수 있습니다.
HTTP 프로토콜의 기본 속성: Stateless
HTTP 프로토콜은 Stateless해서 확장성이 좋다!
언뜻 생각해보면, 이전 요청을 기억하지 않는다는게 안좋게 느껴질 수 있다.
하지만, Stateless하다는 것은 서버가 클라이언트의 상태를 유지할 필요가 없다는 것을 뜻한다.
Cookie)와 응답 헤더(Set-Cookie)를 통해 서버와 주고받음.Set-Cookie를 추가하여 쿠키 전달.sequenceDiagram
participant Client as 클라이언트 (브라우저)
participant Server as 서버
Client->>Server: HTTP 요청 (로그인)
Server-->>Client: HTTP 응답 + Set-Cookie (sessionId=abc123)
Client->>Server: HTTP 요청 + Cookie (sessionId=abc123)
Server-->>Client: 사용자 상태 확인 및 응답
Set-Cookie: sessionId=abc123; Max-Age=3600; Path=/; HttpOnly; Secure
Cookie: sessionId=abc123
@GetMapping("/set-cookie")
public ResponseEntity<String> setCookie(HttpServletResponse response) {
Cookie cookie = new Cookie("username", "홍길동");
cookie.setMaxAge(7 * 24 * 60 * 60); // 7일 유지
cookie.setPath("/"); // 모든 경로에서 유효
cookie.setHttpOnly(true); // JavaScript 접근 불가
cookie.setSecure(true); // HTTPS에서만 전송
response.addCookie(cookie);
return ResponseEntity.ok("Cookie set!");
}
@GetMapping("/get-cookie")
public ResponseEntity<String> getCookie(@CookieValue(value = "username", defaultValue = "Guest") String username) {
return ResponseEntity.ok("Hello, " + username);
}
@GetMapping("/get-all-cookies")
public ResponseEntity<String> getAllCookies(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
System.out.println(cookie.getName() + " = " + cookie.getValue());
}
}
return ResponseEntity.ok("Cookies printed in server logs.");
}
쿠키는 클라이언트(브라우저)에 저장된 데이터이므로 삭제하려면 쿠키의 수명을 설정하거나, 서버에서 동일한 이름과 경로로 만료된 쿠키를 설정해야 합니다.
Max-Age를 0으로 설정하면 브라우저는 즉시 쿠키를 삭제합니다.Expires를 과거 시간으로 설정하면 삭제됩니다.HttpServletResponse로 쿠키 삭제@GetMapping("/delete-cookie")
public ResponseEntity<String> deleteCookie(HttpServletResponse response) {
Cookie cookie = new Cookie("username", null); // 값은 null로 설정
cookie.setMaxAge(0); // 즉시 만료
cookie.setPath("/"); // 경로 일치
response.addCookie(cookie);
return ResponseEntity.ok("Cookie deleted");
}
HttpServletRequest로 쿠키 확인 후 삭제@GetMapping("/delete-specific-cookie")
public ResponseEntity<String> deleteSpecificCookie(HttpServletRequest request, HttpServletResponse response) {
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if ("username".equals(cookie.getName())) {
Cookie deleteCookie = new Cookie("username", null);
deleteCookie.setMaxAge(0); // 즉시 만료
deleteCookie.setPath("/");
response.addCookie(deleteCookie);
}
}
}
return ResponseEntity.ok("Specific cookie deleted");
}
HttpOnly, Secure 속성이 설정된 쿠키는 서버에서만 삭제 가능하며, JavaScript로 삭제할 수 없습니다.Max-Age=0 또는 Expires를 과거로 설정.HttpOnly, Secure 속성이 설정된 쿠키는 서버에서만 삭제 가능.Strict: 쿠키는 동일한 사이트에서만 전송.Lax: 대부분의 크로스 사이트 요청에서 쿠키가 전송되지 않음.None: 크로스 사이트 요청에서도 쿠키 전송(단, Secure 필요).Cookie cookie = new Cookie("sessionId", "abc123");
cookie.setHttpOnly(true);
cookie.setSecure(true);
cookie.setPath("/");
cookie.setMaxAge(3600); // 1시간
response.addCookie(cookie);
| 장점 | 단점 |
|---|---|
| 클라이언트 상태 정보를 쉽게 저장하고 관리 가능 | 용량 제한(4KB) |
| 서버 부하 감소 (상태 정보를 서버에 저장하지 않음) | 클라이언트에서 조작 가능 (보안 문제 발생 가능) |
| 수명 설정 가능 (짧거나 긴 시간 동안 유지 가능) | HTTP를 통해 전송되므로 도청 위험 (HTTPS 필요) |
| 브라우저 간 호환성 높음 | 쿠키의 잘못된 설정으로 보안 문제가 발생할 가능성 있음 |
세션은 비밀번호, 카드번호 등의 중요한 정보는 서버측에서 관리하는 방식입니다. 쿠키만 사용해서 서버와 클라이언트 간 연결을 유지하게 될 경우, 중요한 정보들을 모두 쿠키를 통해 브라우저에 저장하고 있게 됩니다. 따라서 보안적으로 매우 취약하다는 단점을 가지고 있습니다.
이것을 보완해줄 수 있는 것이 session입니다.
중요한 유저의 정보(비밀번호…)는 모두 서버에 저장되어 있고, 클라이언트는 오직 세션 ID만 가지고 있습니다.
session id 자체는 정보를 담고 있지 않기 때문에 외부에서 이를 참조하는 것 만으로는 문제가 되지 않지만, session id를 가로채서 사용자인 척 서버에 요청을 보내는 경우 문제가 생길 수 있습니다.
⭐️ 즉 정리하자면,
클라이언트는 session Id를 쿠키를 통해서 전달받고 저장하며,
브라우저에 세션Id를 저장해둔 클라이언트는 다음 요청때마다
헤더의 cookie에 세션Id를 담아서 전송합니다.
서버는 클라이언트가 보낸 요청의 쿠키에 담긴 세션Id와,
세션 스토리지에 담긴 세션Id를 대조해 인증상태를 판단하는 것입니다.
따라서 세션과 쿠키는 별개의 개념이 아니며, 세션은 쿠키를 기반으로 동작하게 됩니다.
session을 사용할 때의 간단한 flow입니다.

세션 방식을 사용하게 되면, 클라이언트가 로그인에 성공하면 서버는 session id를 생성해 클라이언트 측으로 쿠키를 통해 전송하게 됩니다. 이 경우 cookie는 서버와 클라이언트 간의 매개체이자, 정보를 전달하는 수단이 되게 됩니다.
이후 클라이언트가 서버로부터 요청을 전송할 때, 쿠키를 통해 저장해놓은 session id를 전송하고, 서버에서는 이 session id가 서버 측에 존재하고, 유효하다면 사용자를 식별해 정보를 제공하게 됩니다.
| 특징 | 설명 |
|---|---|
| 저장 위치 | 서버 메모리 또는 외부 저장소(Redis, DB 등). |
| 데이터 수명 | 세션 타임아웃(일정 시간 동안 활동이 없으면 만료). |
| 식별 방식 | 클라이언트는 세션 ID를 쿠키 또는 URL 파라미터를 통해 서버에 전달. |
| 보안 | 세션 데이터는 서버에서 관리되므로 클라이언트는 데이터에 직접 접근할 수 없음. |
| 사용 사례 | 로그인 상태 유지, 장바구니, 폼 데이터 유지 등. |
java의 httpSession class
| 메서드 | 설명 |
|---|---|
setAttribute(String, Object) | 세션에 데이터를 저장. |
getAttribute(String) | 세션에서 데이터를 가져옴. |
removeAttribute(String) | 세션에서 특정 데이터를 제거. |
invalidate() | 세션 무효화(모든 데이터 삭제 및 세션 종료). |
getId() | 현재 세션의 고유 ID를 반환. |
getCreationTime() | 세션 생성 시간을 반환. |
getLastAccessedTime() | 마지막으로 세션에 접근한 시간을 반환. |
application.properties에서 세션 타임아웃을 설정할 수 있습니다.server.servlet.session.timeout=30m # 30분
@Bean
public ServletContextInitializer initializer() {
return servletContext -> {
servletContext.setSessionTimeout(1800); // 30분
};
}
@PostMapping("/login")
public ResponseEntity<String> login(HttpServletRequest request) {
HttpSession oldSession = request.getSession(false);
if (oldSession != null) {
oldSession.invalidate(); // 기존 세션 무효화
}
HttpSession newSession = request.getSession(true); // 새 세션 생성
newSession.setAttribute("user", "홍길동");
return ResponseEntity.ok("Login successful!");
}
서버는 로그인된 유저의 모든 정보를 저장하기 때문에, 이 정보를 사용해 새로운 기능을 추가할 수 있습니다.
예를 들어 특정 유저를 로그아웃 시키고 싶을 때, 세션을 삭제해버릴 수 있습니다. (session id를 클라이언트가 전송해도 유효하지 않으므로 통과되지 않음.)
또한 세션에 로그인된 기기의 정보를 함께 저장하면, 로그인된 디바이스를 모두 보여줘서 원하지 않는 디바이스를 로그아웃 시킬 수 있고, 넷플릭스처럼 계정의 공유 숫자를 제한할 수 있습니다.
즉, 서버 측에서 로그인된 유저의 정보와 권환을 제한하고 control 할 수 있습니다.
CSRF란, Cross Site Request Forgery의 약자로, 한글 뜻으로는 사이트간 요청 위조를 뜻합니다.CSRF는 웹 보안 취약점의 일종이며, 사용자가 자신의 의지와는 무관하게 공격자가 의도한 행위(데이터 수정, 삭제, 등록 등) 을 특정 웹사이트에 요청하게 하는 공격입니다.
조건 : 요청에 필요한 파라미터들을 공격자가 알고 있어야 요청을 조작할 수 있으며, 요청에 필요한 예측 불가능한 파라미터가 없음.
즉, session id를 쿠키를 통해 브라우저에 저장함으로써 발생할 수 있는 문제점입니다.
이러한 공격은 아래오 같은 방법으로 방지할 수 있습니다.
보안 강화 전략을 정리하면 다음과 같습니다.
| 항목 | 쿠키(Cookie) | 세션(Session) |
|---|---|---|
| 저장 위치 | 클라이언트(브라우저) | 서버 |
| 데이터 용량 | 4KB 제한 | 서버 메모리에 의존 |
| 보안 | 클라이언트에서 쉽게 조작 가능 (HTTPS로 전송 암호화 필요) | 클라이언트에서 직접 접근 불가, 서버가 관리 |
| 속도 | 빠름 (클라이언트에 저장) | 상대적으로 느림 (매 요청마다 서버 확인 필요) |
| 유지 시간 | 만료 시간 설정 가능, 브라우저 종료 시 삭제 가능 | 세션 타임아웃 설정 가능 |
| 사용 사례 | 사용자의 기본 설정 저장, 로그인 상태 유지 | 사용자 인증, 장바구니 데이터, 민감한 데이터 처리 |