2024.09.23.월.TIL Cookie Session

김기남·2024년 9월 23일
post-thumbnail

안녕하세요, 오늘은 Cookie 와 Session 에 대해 정리해 보았습니다.

💡 웹 브라우저(크롬, 엣지, 파이어폭스 등)에서 사용자의 컴퓨터에 저장되는 정보. 이 정보는 서버에서 사용자의 브라우저로 전송되고, 브라우저는 해당 정보를 저장해두었다가 이후에 같은 서버에 요청을 보낼 때 마다 함께 전송한다. 쿠키는 사용자의 상태나 세션을 유지하거나 사용자 경험을 개선하기 위해 사용된다.
  • Response 예시
set-cookie: 
sessionId=abcd; 
expires=Sat, 11-Dec-2023 00:00:00 GMT;
path=/; 
domain=notion.so;
Secure
각각의 의미는 아래에서 설명
  • 사용자 로그인 세션 관리, 광고 트래킹 등에 주로 사용된다.
  • Cookie는 모든 HTTP 요청이 발생할 때 마다 항상 서버에 전송된다.
    • 네트워크 트래픽이 추가적으로 발생된다.
    • 최소한의 정보만 사용해야한다.(sessionId, 인증 token)
    • 보안에 취약하다.
  • 서버에 전송하지 않고 브라우저에 단순히 데이터를 저장하고 싶다면?
    • Web Storage를 사용한다. (localStorage, sessionStorage)
      • 보안에 취약하다.
      • 보안에 취약하기 때문에 주민번호와 같은 민감정보를 저장하면 안된다.

쿠키를 사용하지 않는다면?

  1. HTTP는 Stateless(무상태) 특성을 가지고 있다.
  2. Client와 Server가 요청과 응답을 주고받으면 연결이 끊어진다(Connectionless).
  3. Client가 재요청시 Server는 이전 요청을 기억하지 못한다.
  4. Client와 Server는 서로 상태를 유지하지 않는다.
  5. 로그인과 같은 기능은 어떻게 구현되는걸까?
    1. 로그인 했지만 무상태, 비연결 특성으로인해 연결이 유지되지 않는다.
    2. 모든 Request에 사용자 정보를 포함하면 해결이 된다. → Cookie 도입전
    3. 하지만 위와같은 경우 브라우저를 완전히 종료하고 다시 연다면?
  6. 로그인 후에는 유저정보와 관련된 값이 저장되어 있어야겠구나! → Cookie 도입

  • 로그인시 전달된 Request Body Data의 ID, Password로 User 테이블 조회하여 일치여부 확인
  • 인치한다면 Set-Cookie를 활용해 Cookie에 사용할 값 저장
    • ex) 사용자 아이디, 이름 등

  • 로그인 이후에는 모든 요청마다 Cookie를 조회하여
    Request Header에 항상 Cookie 값을 담아서 요청한다
  • Cookie에 담겨있는 값으로 인증/인가 를 진행한다.
  • Set-Cookie : Server에서 Client로 Cookie 전달(Response Header)
  • Cookie : Client가 Server에서 받은 Cookie를 저장하고 HTTP 요청시 Server로 전달(Request Header)

Cookie의 생명주기

  • Set-Cookie: expires=Sat, 11-Dec-2023 00:00:00 GMT;
    • 해당 만료일이 도래하면 쿠키가 삭제된다.
  • Set-Cookie: max-age=3600 (second, 3600초는 한시간. 60 * 60)
    • 0이 되거나 음수를 지정하면 쿠키가 삭제된다.
  • 세션 Cookie : 만료 날짜를 생략하면 브라우저 완전 종료시 까지만 유지된다.(Default)
    • ex) 브라우저를 완전 종료 후 다시 페이지를 방문했을 때 또 로그인을 해야된다
  • 영속 Cookie : 만료 날짜를 입력하면 해당 날짜까지 유지

Cookie의 도메인

쿠키가 아무 사이트에서나 생기고 동작하면 안된다!(필요없는 값 전송, 트래픽 문제 등)

  • ex) domain=notion.so
  • 명시한 문서 기준 도메인 + 서브 도메인 포함
    • domain=notion.so를 지정하여 쿠키 생성
    • notion.so + dev.notion.so와 같은 서브 도메인에도 쿠키 접근
  • 생략하면 현재 문서 기준 도메인만 적용
    • domain=notion.so 에서만 Cookie 접근

Cookie의 경로

  • 1차적으로 도메인으로 필터링 한다. Path는 2차 필터
  • ex) 일반적으로 path=/ 루트(전체)로 지정한다
  • 위 경로를 포함한 하위 경로 페이지만 쿠키 접근
  • path=/api
    • /api → 가능
    • /api/example → 가능
    • /example → 불가능
  • Secure

    • 기본적으로 Cookie는 http, https 구분하지 않고 전송한다.
    • Secure를 적용하면 https인 경우에만 전송한다. s = Secure
  • HttpOnly

    • XSS 공격을 방지한다
    • 자바스크립트에서 접근 불가(브라우저 Console에 document.cookie 사용 불가)
    • HTTP 전송시에만 사용
  • SameSite

    • 비교적 최신 기능이라 브라우저 지원여부를 확인 해야한다.
    • XSRF 공격을 방지한다.
    • 요청 도메인과 쿠키에 설정된 도메인이 같은 경우만 쿠키 전송

로그인 상태 유지


💡 Cookie를 이용한 로그인 상태 유지
  • 한번 로그인에 성공하면 HTTP Response에 쿠키를 담아서 브라우저에 전달한다.
  • 브라우저는 요청마다 Cookie를 함께 전송한다.
  • 실제로는 보안상의 문제로 userId=1과 같은 index 정보를 저장한다. → 이것 또한 보안문제가 있음
    • 세션 Cookie : 만료 날짜를 생략하면 브라우저 완전 종료시 까지만 유지된다.(Default)
      • ex) 브라우저를 완전 종료 후 다시 페이지를 방문했을 때 또 로그인을 해야된다
    • 영속 Cookie : 만료 날짜를 입력하면 해당 날짜까지 유지

요구사항에 맞추어 세션 Cookie를 사용할지 영속 Cookie를 사용할지 결정하면 된다.

  • 코드예시
    • 예시를 위해 ViewTemplate(Thymeleaf)을 사용하는 경우를 가정(SSR)
@Entity
public class User {
	private Long id;

	private String userId; // 로그인 ID

	private String password; // 로그인 비밀번호	

	private String name;
}


@Getter
public class LoginRequest { // DTO
	
	@NotBlank	
	private String id; // 사용자가 입력한 아이디

	@NotNull
	private String pwd; // 사용자가 입력한 비밀번호

}


@Getter
public class UserDto { // Response
	private Long id;
	// 이외 응답에 필요한 데이터들을 필드로 구성하면 된다.
	// 필요한 생성자
}


@Controller
@Requiredargsconstructor
public class UserController {
	
	private final UserService userService;

	@PostMapping("/login")
	public String login(
					@Valid @ModelAttribute LoginRequest request,
					HttpServletResponse response // 쿠키값 세팅에 필요
	) {
		// 로그인 유저 조회
		UserDto loginUser = userService.login(request.getId(), request.getPwd());

		if (loginUser == null) {
			// 로그인 실패 예외처리
			return "login";
		}
		
		// 로그인 성공 처리
		// 쿠키 생성, Value는 문자열로 변환하여야 한다.
		Cookie cookie = new Cookie("userId", String.valueOf(loginMember.getId()));
		
		// 쿠키에 값 세팅 (expire 시간을 주지 않으면 세션쿠키가 됨, 브라우저 종료시 로그아웃)
		// Response Set-Cookie: userId=1 형태로 전달된다.
		response.addCookie(cookie);

		return "redirect:/"; // 메인페이지로 리다이렉트
	}
	
}


@Service
@Requiredargsconstructor
public class UserService {

	private final UserRepository userRepository;

	public UserDto login(String inputId, String inputPwd) {

		// 1. 유저 조회
		// 2. 입력한 값과 유저의 비밀번호 일치여부 조회
		// 3. 일치하지 않으면 예외처리
		// 3-1. 일치하면 return Type인 UserDto에 맞추어 Controller로 전달
		return new UserDto(user);
	}

}
  • 로그인에 성공하면 쿠키를 생성하고 HttpServletResponse 객체에 에 담는다.
    • Response Header를 확인해보면 Set-Cookie: userId=1 형태로 전달된다.
  • Cookie 이름(Key값)은 userId 이고 회원 index 값을 담아둔다.
  • 만료 시간을 지정하지 않아서 세션 쿠키로 만들어진다.
    • 브라우저 종료 전까지 userId 가 모든 Request Header Cookie에 담겨서 전달된다.
  • 저장된 쿠키를 사용하는 API 예시
    • 요구사항
      • 로그인한 회원이면 home 페이지로 이동(메인(home) 페이지를 보려면 로그인 필수)
      • 로그인하지 않은 회원이면 login 페이지로 이동
@Controller
@Requiredargsconstructor
public class HomeController {

	private UserService userService;
	
	@GetMapping("/")
	public String home(
				// @CookieValue(required = true) 로 필수값(default) 설정
				// required = false 이면 필수값 아님.
				@CookieValue(name = "userId", required = false) Long userId, // String->Long 자동 타입컨버팅
				Model model
	) {
		
		// 쿠키에 값이 없으면 로그인 페이지로 이동 -> 로그인 X
		if(userId == null) {
			return "login";
		}
		
		// 실제 DB에 데이터 조회 후 결과가 없으면 로그인 페이지로 이동 -> 일치하는 회원정보 X
		UserDto loginUser = userService.findById(userId);

		if(loginUser == null) {
			return "login";
		}

		// 정상적으로 로그인 된 사람이라면 View에서 사용할 데이터를 model 객체에 데이터 임시 저장
		model.addAttribute("loginUser", loginUser);
		// home 화면으로 이동
		return "home";
		
	}
}
  • View에서는 model 객체에 담겨있는 loginUser 를 활용하여 변수로 사용할 수 있다.

    • 위 예시는 SSR 기술사용, ViewTemplate(Thymeleaf) 사용시
    • ex) HTML 내부에 “ ${loginUser.getName()}님 환영합니다. “ 과같은 코드가 있음
    • 우리가 현재까지 실습했던 파일들의 HTML 내부에도 위와같은 코드를 찾아볼 수 있다!
  • 로그아웃 기능

// HTML 예시
<html>
	<body>
		<form action="/logout" method="post">
			<button type="submit">
				로그아웃
			</button>
		</form>
	<body>
</html>


@Controller
@Requiredargsconstructor
public class UserController {
	
	private final UserService userService;

	@PostMapping("/login")
	public String login(
					@Valid @ModelAttribute LoginRequest request,
					HttpServletResponse response
	) {
		// 위 예시코드에 나와있음
	}

	@PostMapping("/logout")
	public String logout(
					HttpServletResponse response
	) {
		Cookie cookie = new Cookie("userId", null);
		cookie.setMaxAge(0); // 0초로 쿠키를 세팅하여 사라지게 만듬
		response.addCookie(cookie);

		return "redirect:/"; // 메인페이지로 이동
	}
	
}
  • 쿠키가 0초만 유지되도록 변경되어서 만료된다. → 저장된 userId 쿠키가 삭제된다.

쿠키의 보안 문제

💡 현재는 Cookie를 사용한 위와같은 로그인 방식을 구현하지 않는다. 큰일난다! 왜그럴까?
  1. 쿠키 값은 임의로 변경할 수 있다.
    1. 위 예시코드와 같은 방식을 사용하면
      Client가 임의로 쿠키의 값을 변경하면 서버는 다른 유저로 인식한다.
      userId = 내맘대로 수정가능
  • 브라우저 → 개발자도구 → Application 탭 → Storage/Cookies/URL → 값 조정 가능
  • 실제로는 암호화되어 저장되어있는 Value들을 볼 수 있다!
  1. Cookie에 저장된 Data는 탈취되기 쉽다.
    • 민감한 정보가 있다면?
    • 내 컴퓨터 쿠키를 누가 본다면?
    • 쿠키는 네트워크 전송 구간에서 탈취될 확률이 매우 높다. → HTTPS를 사용하는 이유중 하나
    • 한번 탈취된 정보는 변경이 없다면 반영구적으로 사용할 수 있다.
      • ex) Cookie : 주민번호
      • ex) userId = 1

보안 대처방법

  1. 쿠키에 중요한값을 저장하지 않는다.
  2. 사용자 별로 일반 유저나 해커들이 알아보지 못하는 값을 노출한다.
    → 보통 암호화된 Token을 쿠키에 저장한다. → Access Token, Refresh Token
  3. 서버에서 암호화된 Token과 사용자를 매핑해서 인식한다.
  4. Token은 서버에서 관리한다.(생성[만료시간 등], 검증)
  5. 토큰은 해커가 임의의 값을 넣어도 동작하지 않도록 만들어야 한다. →
    JWT : ADSFSADFKJLJ!@#LKAJSDFLKAJSASDASDFASD
  6. 해커가 토큰을 탈취해도 사용할 수 없도록 토큰 만료시간을 짧게 설정한다.
  7. 탈취가 의심되는 경우 해당 토큰을 강제로 만료시키면 된다.
    ex) 접속기기 혹은 IP가 다른 경우 등 → Logic

Session

💡 Cookie를 사용한 방식은 여러가지 보안 문제가 있다. 결국 보안 문제를 해결하려면 중요한 정보는 모두 서버에서 저장해야한다. Client와 서버는 예측이 불가능한 임의의 값으로 연결해야 한다.
  • 서버에서 중요한 정보를 보관하며 로그인 연결을 유지하는 방법을 Session이라고 한다.
  • 앞서 배운 Cookie는 중요한 정보를 Client측에서 보관하고 있는것이다.
    • ex) userId = 1

Session 동작 방식

  • 로그인에 성공하면 Server에서 임의로 만든 Session ID를 생성한다.
    • Session ID는 예측이 불가능해야 한다.
    • 이미 사용해보았던 UUID와 같은 값을 활용한다.
  • 생성된 Session ID와 조회한 User 인스턴스를 서버의 Session 저장소에 저장한다.
    • 서버에 유저와 관련된 중요한 정보를 저장한다.

실제 동작방식

  1. 로그인
  • 결국 Session Id로 연결 상태유지를 위해 Cookie를 사용한다.
    • 서버는 클라이언트에 Set-Cookie: SessionId=임의생성값 을 전달한다.
    • 클라이언트는 Cookie 저장소에 전달받은 값을 저장한다.
  • 세션의 아주 중요한 포인트는 유저와 관련된 정보는 클라이언트에 하나도 없다는것!
  1. 로그인 이후 요청
  • 클라이언트는 모든 요청에 SessionId Cookie를 전달한다.
  • 서버에서는 쿠키를 통해 전달된 SessionId로 Session 저장소를 조회한다.
  • 로그인시 저장하였던 Session 정보를 서버에서 사용한다.

정리

  • Session을 사용하여 서버에서 민감한 정보들을 저장하게 되었다.
    1. 예상 불가능한 세션 ID를 사용하여 쿠키값을 변조해도 문제가 없다.
    2. Session ID가 탈취되어도 중요한 정보는 들어있지 않다.
    3. Session ID가 탈취되어도 시간이 지나면 세션이 만료되도록 설정 하면된다.
      1. 특정 주기(30분)마다 사용되지 않은 Session 제거 → 무의미한 요청이 된다.
    4. Session ID가 탈취되어도 해킹이 의심되는 경우 해당 세션을 제거하면 된다.
  • Session은 특별한것이 아니라 단지 Cookie를 사용하여 클라이언트가 아닌
    서버에서 데이터를 저장해두는 방법이다.
  • Session을 코드로 직접 구현할 수는 있지만 모두가 예상할 수 있듯이
    당연히 Servlet은 Session 을 자체적으로 지원한다.

Servlet HttpSession


💡 Servlet이 공식적으로 지원하는 Session인 `HttpSession` 대해 알아보자. HttpSession에는 Session 기능 구현에 필요한 많은 기능들을 지원한다.
  1. Servlet을 통해 HttpSession 을 생성하게되면
    위 예시에서 본 SessionId 가 → JSESSIONID로 생성된다.
  2. JSESSIONID의 Value는 예측 불가능한 랜덤값으로 생성된다.

ex) JSESSIONID = WLRMATLRKSQKA10TIDIRMSDLTKDDB

  • 코드예시
    • 참고
      • 상수 값들을 관리하는 클래스
      • 상수로 활용할 class는 인스턴스를 생성(new)하지 않는다.
      • abstract 추상클래스 혹은 interface 로 만들어 상수값만 사용하도록 만들어두면 된다.
// 추상클래스 -> 됨
public abstract class Const {
	public static final String LOGIN_USER = "loginUser";
}

// 인터페이스 -> 됨
public interface Const {
	String LOGIN_USER = "loginUser";
}

// 클래스 -> 안됨
public class Const { // new Const();
	public static final String LOGIN_USER = "loginUser";
}

// Const.LOGIN_USER; O / new Const(); X
@Getter
public class LoginRequestDto {
	
	@NotBlank	
	private String id; // 사용자가 입력한 아이디

	@NotNull
	private String pwd; // 사용자가 입력한 비밀번호

}

@Controller
@Requiredargsconstructor
public class UserController {

	private final UserService userService;

	@PostMapping("/login")
	public String login(
		@Valid @ModelAttribute LoginRequestDto dto,
		HttpServletRequest request
	) {
		
		User loginUser = loginService.login(dto.getId(), dto.getPwd());
		// 실패시 예외처리		

		// 로그인 성공시 로직
		// Session이 request에 존재하면 기존의 Session을 반환하고, 
		// Session이 request에 없을 경우에 새로 Session을 생성한다.
		HttpSession session = request.getSession(); // default true => session 생성
		
		// Session에 로그인 회원 정보를 저장한다.
		session.setAttribute(Const.LOGIN_USER, loginUser);
		
		// 로그인 성공시 리다이렉트
		return "redirect:/";
	}
}
  • request.getSession();
    - default 값은 true 이다.

  • request.getSession(true);

    • Request 객체 내에 Session이 존재한다면 기존 Session을 반환
    • Request 객체 내에 Session이 없으면 새로운 Session을 생성해서 반환
    • Default
  • request.getSession(false);

    • Request 객체 내에 Session이 존재한다면 기존 Session을 반환
    • Request 객체 내에 Session이 없으면 null을 반환
  • session.setAttribute(Const.LOGIN_USER, loginUser);

    • Session에 Data를 저장하는 방법 전에 배운 request.setAttribute(); 와 비슷함
    • 하나의 Session에 여러개의 데이터를 메모리에 저장할 수 있다.
  • 로그아웃

@Controller
@Requiredargsconstructor
public class UserController {

	private final UserService userService;

	@PostMapping("/logout")
	public String logout(
		HttpServletRequest request
	) {
		
		HttpSession session = request.getSession(false);
		// 세션이 존재하면 -> 로그인이 된 경우
		if(session != null) {
			session.invalidate(); // 해당 세션(데이터)을 삭제한다.
		}
		
		return "redirect:/";
	}
}
  • 로그인 후 사용할 API
    • 요구사항
      • 로그인한 회원이면 home 페이지로 이동(”home” 페이지를 보려면 로그인 필수)
      • 로그인하지 않은 회원이면 login 페이지로 이동
@Controller
@Requiredargsconstructor
public class HomeController {

	private UserService userService;
	
	@GetMapping("/")
	public String home(
		HttpServletRequest request,
		Model model		
	) {
		
		// default인 true로 설정되면 로그인하지 않은 사람들도 값은 비어있지만 세션이 만들어진다.
		// session을 생성할 의도가 없다.
		// session은 Memory를 사용하기 때문에 막 사용하면 안된다! 리소스 낭비!
		request.getSession(false);
		
		// session이 없으면 로그인 페이지로 이동
		if(session == null) {
			return "login";
		}
		
		// session에 저장된 유저정보 조회
		// Object loginUser = session.getAttribute(Const.LOGIN_USER);
		
		// 반환타입이 Object여서 Type Casting이 필요하다.
		User loginUser = (User)session.getAttribute(Const.LOGIN_USER);

		// Session에 유저 정보가 없으면 login 페이지 이동
		if (loginUser == null) {
			return "login";
		}

		// Session이 정상적으로 조회되면 로그인된것으로 간주
		model.addAttribute("loginUser", loginUser);
		// home 화면으로 이동
		return "home";
		
	}
}

Spring의 Session


💡 Spring에서는 Session을 쉽게 다루도록 `@SessionAttribute`라는 어노테이션이 제공된다.
  • 해당 어노테이션은 Session을 새로 생성하는 기능은 없다.

  • 이미 로그인된 사용자를 찾는 경우 즉, 이미 Session이 있는 경우에 사용한다.

  • 코드예시

    로그인 후 사용할 API

    • 요구사항
      • 로그인한 회원이면 home 페이지로 이동(”home” 페이지를 보려면 로그인 필수)
      • 로그인하지 않은 회원이면 login 페이지로 이동
@Controller
@Requiredargsconstructor
public class HomeController {

	private UserService userService;
	
	@GetMapping("/")
	public String home(
		// Session이 필수값은 아니다. 로그인 했거나 안했거나 판별해야하니 required false
		@SessionAttribute(name = Const.LOGIN_USER, required = false) User loginUser,
		Model model	
	) {
		
		// session에 loginUser가 없으면 Login 페이지로 이동
		if (loginUser == null) {
			return "login";
		}
		

		// Session이 정상적으로 조회되면 로그인된것으로 간주
		model.addAttribute("loginUser", loginUser);
		// home 화면으로 이동
		return "home";
		
	}
}

처음 로그인을 시도하는 경우

  • 완전히 처음 로그인을 시도하는 경우 URL 뒤에 “JSSESSIONID=값”이 함께 전달된다.

    • ex) http://localhost:8080/jsessionId=임의로 생성된값
    • 해당 값은 굳이 필요가 없다. 내부적으로 Set-Cookie로 SessionID와 값을 넣어주기 때문
    • 위의 경우는 브라우저에서 Cookie를 지원하지 않는 경우를 대비한 기능이다.
    • Cookie를 지원하지 않으면 URL을 통해 Session을 유지하는 방법에 사용된다.
      • 하지만 사용하려면 모든 요청 URL에 jsessionId값이 전달 되어야한다.
    • View(Thymeleaf) → Template Engine을 사용하면 jsessionId를 URL에 자동으로 포함한다.
  • 서버의 입장에서는 클라이언트의 브라우저가 Cookie를 지원하는지 여부를 확인할 수 없기때문에
    최초 로그인 시도시에는 Cookie값과 함께 URL에 값을 함께 전달되는것.

  • 당연히 URL에 값을 담아주지 않도록 설정할 수 있다.

    • application.properties
server.servlet.session.tracking-modes=cookie
  • application.properties
server: 
	servlet: 
		session: 
			tracking-modes: cookie
			

항상 URL이 아닌 Cookie를 통해서만 Session을 유지하고자 할 때 위 설정을 사용하면 된다.

Session 정보


💡 HttpSession이 가지고 있는 정보는 어떤것이 있는지 알아보자.
@Slf4j
@RestController
public class SessionController {

	@GetMapping("/session")
	public String session(HttpServletRequest request) {
		HttpSession session = request.getSession(false);
		if (session == null) {
			return "no session";
		}
		
		// session 정보 조회
	}
}
  1. session.getId(); : jsessionId 값을 조회할 수 있다.
    • ex) ASD2FLKJ3AS4DL5FK23ASDFASDF
  2. session.getMaxInactiveInterval(); : 세션의 유효시간
    • ex) second 단위 default는 30분(1800초)이다.
  3. session.getCreationTime(); : 세션 생성시간
    • ex) Sat Dec 9 15:40:23 KST 2023
  4. session.getLastAccessedTime(); : 해당 세션에 마지막으로 접근한 시간
    • ex) Sat Dec 9 15:40:23 KST 2023
  5. session.getIsNew(); : 새로 생성된 세션인지 여부
    • 새로 만들었으면 true, 기존 세션이면 false

Session TimeOut


💡 Session은 logout 기능을 사용하여 `session.invalidate();` 가 되어야 삭제된다. 하지만 대부분의 사용자들은 로그아웃을 굳이 하지않고, 브라우저를 종료한다.
  • HTTP는 Connectionless 특성을 가지고 있기때문에
    서버 입장에서는 브라우저 종료 여부를 판별하지 못한다.
  • 즉, 서버에서 Session을 언제 삭제해야 하는지 판단하기 힘들다.
  • JSESSIONID의 값을 탈취 당한 경우 해당 값으로 악의적인 요청을 할 수 있다.
  • 세션은 서버 메모리에 생성된다. 서버의 자원(리소스)은 한정적이기 때문에
    꼭 필요한 경우만 생성해서 사용해야 한다.
    ex) 로그인한 유저가 100만명 이라면..?

세션 생명주기

기본적으로 30분을 기준으로 세션을 삭제한다.
하지만 이런 경우 실제 로그인 후 30분 이상의 시간동안 사용중인 사용자의 세션 또한 삭제될 것이다.
즉, 다시 로그인 해야하는 경우가 발생한다.

  • 대처방법
    • 세션 생성시점 30분이 아니라 서버에 최근 Session을 요청한 시간을 기준으로 30분을 유지해준다. → HTTP 요청을 할때마다 해당 시점으로부터 30분으로 만료시간이 다시 세팅되는것.
    • HttpSession은 기본적으로 해당 방식으로 세션의 생명주기를 관리한다.
  • 위에서 본 Session 정보에서 LastAccessedTime 을 기준으로 30분이 지나면
    WAS가 내부적으로 세션을 삭제한다.

정리

  1. 세션은 메모리를 사용한다. → 최소한의 데이터만 저장해야 한다.
    1. 세션이 많아지면 서버의 장애가 발생할 수 있다.(메모리 리소스 부족)
  2. HttpSession은 LastAccessedTime을 기준으로 30분의 생명주기를 가지고 있다.
  3. 세션의 시간을 너무 오래 유지하여도 메모리 리소스가 부족할 수 있다.
    1. 적당한 시간 설정이 꼭 필요하다. Default 30분

쿠키 (Cookie)

  • 정의: 웹 브라우저(Client 측)에 저장되는 데이터
  • 용도: 사용자의 방문 기록, 로그인 상태 유지, 개인 맞춤 설정 등을 저장. (HTTP 특성 극복), 광고 정보(광고회사)
  • 특징: 클라이언트 측에 저장되며, 서버에 요청을 보낼 때마다 포함되어 전송됨.
  • 수명: 만료 날짜를 설정할 수 있음,
    세션 쿠키(브라우저 종료 시 삭제)와 영속 쿠키(지정된 기간 동안 유지)로 구분됨.

세션 (Session)

  • 정의: 사용자와 서버 간의 상태를 유지하기 위한 방법.
  • 용도: 로그인 정보, 사용자 활동 등을 서버 측에서 관리.
  • 특징: 서버 측에서 저장되며, 세션 ID가 쿠키에 저장되어 클라이언트와 연결됨.
  • 수명: 브라우저를 닫거나 일정 시간이 지나면 만료됨.

오늘의 코드카타

class Solution {

public int solution(int num, int n) {
    int answer = 0;
    if (num % n == 0) {
        answer = 1;
    } else {
        answer = 0;
    }
    return answer;
}

}

public class Main {

public static void main(String[] args) {

    Solution solution = new Solution();

    System.out.println(solution.solution(98, 2));
    System.out.println(solution.solution(34, 3));
}

}

n의 배수

profile
새로운 시작~!

0개의 댓글