📙 목차
1. Cookie
Cookie (쿠키)
- 웹 서버가 사용자의 웹 브라우저에 저장하는 작은 데이터 조각
- 클라이언트와 서버 간의 상태 정보를 유지하거나 추적하기 위해 사용된다.
Cookie 특징
- 사용자의 상태 정보(예: 로그인 정보, 설정 값 등)를 클라이언트 측에 저장한다.
- HTTP가 기본적으로 상태 비저장(stateless)이기 때문에, 상태 유지를 위해 사용한다.
- 서버가 응답 헤더에 Set-Cookie를 보내면, 브라우저가 이를 저장하고 이후 요청 시 Cookie 헤더로 함께 전송한다.
Cookie 기본 구조 (HTTP Header 기준)
Set-Cookie: <name>=<value>; <attribute1>; <attribute2>; ...
Set-Cookie: sessionId=abc123; Path=/; HttpOnly; Secure; Max-Age=3600; SameSite=Lax
Cookie 구성 요소
구성 요소 | 필수 | 설명 |
Name | ✔️ | 쿠키의 이름이다. 예: sessionId |
Value | ✔️ | 쿠키에 저장할 값이다. 예: abc123 |
Path | ❌ | 이 경로 이하의 요청에서만 쿠키가 전송된다. ex: /, /user기본값은 현재 경로이다. |
Domain | ❌ | 쿠키를 전송할 도메인을 지정한다. ex: .example.com으로 설정하면 서브도메인에도 전송된다. 기본값은 현재 요청의 호스트이다. |
Expires | ❌ | 쿠키의 만료 날짜를 명시적으로 설정한다. 형식: Wdy, DD Mon YYYY HH:MM:SS GMT ex: Wed, 21 Oct 2025 07:28:00 GMT |
Max-Age | ❌ | 쿠키의 유효 시간을 초 단위로 설정한다. 0이면 즉시 삭제된다. Expires보다 우선 적용된다. |
Secure | ❌ | 이 속성이 있으면 HTTPS에서만 쿠키가 전송된다. |
HttpOnly | ❌ | JavaScript에서 document.cookie로 접근할 수 없도록 막는다. (보안 강화: XSS 방지) |
SameSite | ❌ | 쿠키가 cross-site 요청 시 전송되는지를 제어한다. - Strict: 완전 차단 - Lax: 일부 허용 (GET 링크 등) - None: 모두 허용 (단, Secure 필수) |
* Cookie의 문제점
- 쿠키 값은 클라이언트가 임의로 변경할 수 있다.
- 사용자가 브라우저 개발자 도구(F12) → Application → Cookies에서 직접 값 수정 가능
- 예: userId 값을 해커가 다른 유저로 변경 가능
- 쿠키에 저장된 데이터는 네트워크 구간에서 탈취되기 쉽다.
- userId 같은 민감 정보 저장 위험
- HTTPS 미사용 시 탈취 위험 극대화
- 탈취된 쿠키는 만료되지 않는 한 지속적으로 악용 가능
* 보안 대처방법
- 쿠키에 중요한 정보를 직접 저장하지 않는다.
- 암호화된 토큰(Token)을 저장한다.
- 서버에서 토큰과 사용자 정보를 매핑하여 인증 처리
- 토큰 값은 유추하거나 임의로 생성 불가능하게 만든다.
- 토큰 위조 방지
- 해커가 임의 토큰을 넣어도 동작하지 않도록 검증 로직 구현
- 토큰 만료시간을 짧게 설정하여 탈취 피해 최소화
- 탈취 의심 시 토큰 강제 만료 처리
- IP, 접속 기기 정보 등으로 의심 활동 감지 후 차단 가능
2. Cookie 사용 예제
쿠키 생성 (Set-Cookie)
@GetMapping("/set-cookie")
public ResponseEntity<String> setCookie(HttpServletResponse response) {
Cookie cookie = new Cookie("username", "alice");
cookie.setPath("/");
cookie.setHttpOnly(true);
cookie.setMaxAge(60 * 60); // 1시간
response.addCookie(cookie);
return ResponseEntity.ok("쿠키가 설정되었습니다.");
}
쿠키 읽기 (Cookie 헤더에서)
@GetMapping("/get-cookie")
public ResponseEntity<String> getCookie(@CookieValue(name = "username", defaultValue = "guest") String username) {
return ResponseEntity.ok("저장된 사용자 이름: " + username);
}
쿠키 삭제 (MaxAge = 0)
@GetMapping("/delete-cookie")
public ResponseEntity<String> deleteCookie(HttpServletResponse response) {
Cookie cookie = new Cookie("username", null);
cookie.setPath("/");
cookie.setMaxAge(0); // 삭제
response.addCookie(cookie);
return ResponseEntity.ok("쿠키가 삭제되었습니다.");
}
실전 예제
@RestController
public class LoginController {
// 로그인: 쿠키 생성
@GetMapping("/login")
public ResponseEntity<String> login(@RequestParam String userId, HttpServletResponse response) {
Cookie cookie = new Cookie("userId", userId);
cookie.setPath("/");
cookie.setMaxAge(60 * 60); // 1시간 유지
cookie.setHttpOnly(true); // JS에서 접근 못하게 (보안)
response.addCookie(cookie);
return ResponseEntity.ok(userId + "님 로그인 성공");
}
// 마이페이지: 쿠키에서 로그인 여부 확인
@GetMapping("/mypage")
public ResponseEntity<String> mypage(@CookieValue(name = "userId", required = false) String userId) {
if (userId == null) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("로그인이 필요합니다.");
}
return ResponseEntity.ok(userId + "님의 마이페이지입니다.");
}
// 로그아웃: 쿠키 삭제
@GetMapping("/logout")
public ResponseEntity<String> logout(HttpServletResponse response) {
Cookie cookie = new Cookie("userId", null);
cookie.setPath("/");
cookie.setMaxAge(0); // 삭제
response.addCookie(cookie);
return ResponseEntity.ok("로그아웃 되었습니다.");
}
}
3. Session
Session (세션)
- 웹에서 사용자의 상태 정보를 서버에 저장하여 관리하는 기술
- 서버가 특정 클라이언트를 구분하고 그 상태를 기억하도록 해준다.
- 서버는 클라이언트에게 고유한 세션 ID(Session ID)를 발급하고, 이를 통해 사용자의 상태 데이터를 서버에 저장한다.
- 클라이언트는 보통 이 세션 ID를 쿠키(cookie) 형태로 저장하고 요청 시 서버에 전달한다.
Session 특징
- 중요한 사용자 정보는 서버에 저장되므로 보안에 유리하다.
- 클라이언트에는 세션 ID만 저장되어 데이터 위변조 위험이 적다.
- 서버 자원을 사용하기 때문에 대규모 서비스 시에는 세션 관리와 확장성 고려가 필요하다.
Session 구성 요소
구성요소 | 역할 및 설명 | 특징 및 주의점 |
Session ID | 클라이언트를 고유하게 식별하는 문자열로, 서버가 생성하여 클라이언트에 전달한다. | 랜덤하고 예측 불가능한 값이어야 하며, 쿠키에 저장되어 요청 시 서버에 전달된다. 보안을 위해 HTTPS, HttpOnly, Secure 옵션 적용 권장. |
Session 객체 | 사용자별 상태 정보를 키-값 쌍 형태로 저장하는 서버 내 데이터 컨테이너이다. | 로그인 정보, 권한, 장바구니 등 사용자 상태 정보를 저장한다. 서버 내 API로 접근 및 수정 가능하다. |
Session 저장소 | 세션 객체를 저장하는 공간으로 메모리, DB, 분산 캐시 등 다양한 방식이 있다. | 메모리: 빠르나 서버 재시작 시 데이터 소실 DB/분산 캐시: 영속성 및 확장성 우수, 대규모 서비스에 적합 |
만료 시간 (Timeout) |
세션이 활성 상태로 유지되는 최대 시간을 제한하며, 일정 시간 무요청 시 세션을 만료시킨다. | 보안을 위해 적절한 시간 설정이 중요하다. 만료 후에는 세션 데이터 삭제 또는 무효화되어 새로운 세션이 생성된다. |
세션 관리기 | 세션 생성, 조회, 검증, 만료 처리를 담당하는 서버 내부 모듈이다. | 세션 ID 중복 방지, 유효성 검사, 만료 관리 등을 수행한다. 세션 저장소와 연동하여 세션 상태를 관리한다. |
Session TimeOut
- Session의 문제점
- HTTP는 Connectionless 특성을 가지고 있어서 서버가 브라우저 종료 여부를 판별하지 못한다.
- 따라서 세션을 언제 삭제해야 할지 서버 입장에서는 판단하기 어렵다.
- JSESSIONID가 탈취되면 악의적인 요청에 악용될 수 있다.
- 세션은 서버 메모리를 사용하므로 많은 사용자가 동시에 접속하면 서버 자원이 급격히 소모된다.
- Session 생명주기
- 세션은 기본적으로 30분 동안 유지되며, 그 이후에는 자동 삭제된다.
- 사용자가 로그인 후 아무 활동이 없으면 30분이 지나 세션이 만료되고 재로그인이 필요할 수 있다.
- HttpSession의 생명주기 관리
- HttpSession은 세션 생성 시점 기준이 아니라, 가장 최근 요청 시간(LastAccessedTime) 을 기준으로 30분을 유지한다.
- 사용자가 활동할 때마다 세션 유효 시간이 갱신되며, 마지막 접근 시점으로부터 30분이 지나야 세션이 자동 만료된다.
Session의 한계
- 서버는 요청마다 DB나 메모리에 저장된 세션 정보를 조회하므로 오버헤드가 발생한다.
- 서버가 사용자의 상태를 유지해야 하므로 동시 접속자가 많을수록 부담이 커진다.
- 세션은 주로 웹 브라우저 기반이기 때문에, 모바일 앱 등 다양한 클라이언트에서 인증 처리에 제한이 있다.
- 서버를 여러 대로 확장하는 수평 확장(Scale Out) 환경에서는 세션 정보를 서버 간에 공유하기 어렵다.
* 오버헤드
- 어떤 작업을 수행하기 위해 추가로 소모되는 간접적인 시간, 자원(메모리, CPU 등), 처리 비용을 의미한다.
- 본래 목적을 달성하기 위한 핵심 작업 외에 부수적으로 필요한 처리나 자원 사용을 말한다.
- 오버헤드가 많으면 시스템 성능이 저하되고 효율이 떨어진다.
- ex. 서버가 사용자 세션 정보를 매번 조회하는 것
4. Session 사용 예제 1 - Servlet
Servlet의 HttpSession
- HttpSession은 서블릿에서 클라이언트별 상태를 서버에 저장하고 관리하기 위한 인터페이스이다.
- HttpSession을 사용해 사용자의 상태를 서버에 저장하고 여러 요청에 걸쳐 유지할 수 있다.
- 특징
- 서버가 클라이언트에게 고유한 세션 ID를 발급하여, 이를 쿠키(JSESSIONID)로 클라이언트에 전달한다.
- 클라이언트는 이후 요청 시 이 세션 ID를 서버로 보내고, 서버는 해당 ID로 세션 객체를 찾아 사용자 상태를 관리한다.
- HttpSession 객체를 통해 세션에 데이터를 저장(setAttribute)하거나 조회(getAttribute)할 수 있다.
- 세션은 일정 시간 무활동 시 자동 만료된다.
// 로그인 처리 서블릿
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String id = req.getParameter("id");
String pw = req.getParameter("pw");
if ("user".equals(id) && "1234".equals(pw)) {
HttpSession session = req.getSession();
session.setAttribute("user", id); // 로그인 성공 시 세션에 저장
resp.getWriter().println("로그인 성공");
} else {
resp.getWriter().println("로그인 실패");
}
}
}
// 로그인 상태 확인 서블릿
@WebServlet("/profile")
public class ProfileServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
HttpSession session = req.getSession(false);
resp.setContentType("text/html;charset=UTF-8");
if (session != null && session.getAttribute("user") != null) {
String user = (String) session.getAttribute("user");
resp.getWriter().println(user + "님, 환영합니다!");
} else {
resp.getWriter().println("로그인 필요");
}
}
}
5. Session 사용 예제 2 - Spring
Spring 에서 Session 사용 방법
- HttpSession
- @SessionAttribute
HttpSession
@Controller
public class SessionController {
// 로그인 처리 및 세션 저장
@GetMapping("/login")
public String login(HttpSession session) {
session.setAttribute("username", "user123");
return "redirect:/welcome";
}
// 세션에서 직접 값 꺼내 사용
@GetMapping("/welcome")
public String welcome(HttpSession session) {
String username = (String) session.getAttribute("username");
System.out.println("환영합니다, " + username + "님!");
return "welcome";
}
}
* HttpSession을 통해 확인할 수 있는 세션 정보
메서드 | 설명 |
getId() | 세션의 고유 ID (JSESSIONID)를 반환한다. |
getMaxInactiveInterval() | 세션의 유효 시간(초)을 반환한다.기본값은 1800초 (30분)이다. |
getCreationTime() | 세션이 최초로 생성된 시간을 반환한다.예: Sat Dec 9 15:40:23 KST 2024 |
getLastAccessedTime() | 클라이언트가 마지막으로 세션에 접근한 시간을 반환한다.예: Sat Dec 9 15:40:23 KST 2024 |
isNew() | 해당 세션이 새롭게 생성된 것인지 여부를 boolean 값으로 반환한다. |
@SessionAttribute
@Controller
public class SessionAttrController {
// 로그인 처리 및 세션 저장
@GetMapping("/login")
public String login(HttpSession session) {
session.setAttribute("username", "user123");
return "redirect:/welcome";
}
// 세션에서 값을 바로 인자로 주입받음
@GetMapping("/welcome")
public String welcome(@SessionAttribute("username") String username) {
System.out.println("환영합니다, " + username + "님!");
return "welcome";
}
}
'Spring > 강의' 카테고리의 다른 글
[📙 숙련 Spring] 2-4. Filter (0) | 2025.05.20 |
---|---|
[📙 숙련 Spring] 2-3. Token, JWT(JSON Web Token) (0) | 2025.05.16 |
[📙 숙련 Spring] 2-1. 인증과 인가 (0) | 2025.05.16 |
[📙 숙련 Spring] 1-3. Validation과 Bean Validation (4) | 2025.05.15 |
[📙 숙련 Spring] 1-2. Spring Bean 등록 (0) | 2025.05.15 |