쿠키(Cookie)와 세션(Session)

Legday_Dev·2023년 10월 23일
0

Spring

목록 보기
14/14
post-thumbnail

목표 : 웹 어플리케이션에서 로그인을 처리할 때 쿠키와 세션을 어떻게 사용하는지 정리

쿠키(Cookie)

  • HTTP 는 무상태(Stateless) 프로토콜이기 때문에 요청과 응답이 끝나면 연결이 끊긴다.
  • 클라이언트 입장에서 로그인을 한다면 매번 요청을 할 때마다 로그인정보를 서버에게 넘겨줘야 한다.
  • 쿠키(Cookie)를 이용하면 클라이언트는 매번 로그인정보를 가지고 요청할 필요가 없다.
  • 위와 같이 한번 로그인정보를 담아서 서버로 요청하면 서버에서 쿠키를 생성해서 웹브라우저(클라이언트)에게 응답을 해준다.
  • 웹 브라우저에 쿠키 저장소에 쿠키정보가 담기면서 이후에 통신을 할 때는 HTTP 헤더에 쿠키가 담겨서 서버와 통신하게 된다.

쿠키 생성 로직

쿠키는 로그인구현을 담당하는 컨트롤러에서 생성후 HttpServletResponse 객체에 담아서 응답해주면 된다.

  • 로그인을 담당하는 컨트롤러에서 유효성검사 등 로그인 로직을 구현하고 마지막에 쿠키를 생성해서 response 객체에 담아서 응답해주면 된다.
  • Cookie 객체 2번재 파라미터는 String 타입이 와야하기 때문에 로그인객체의 id값인 int 형을 String 으로 형변환 하였다.
  @PostMapping("/login")
  public String login(@Valid @ModelAttribute LoginForm form, BindingResult bindingResult, HttpServletResponse response){
  // 생략 ...

  // 로그인 성공 처리(세션 쿠키) -> 브라우저 종료 시 모두 종료
  Cookie idCookie = new Cookie("memberId", String.valueOf(loginMember.getId()));
  response.addCookie(idCookie);

  return "redirect:/";
  }
  • 쿠키를 조회하는 건 Spring에서 제공하는 @CookieValue 어노테이션을 사용하면 된다.
  • name 옵션에는 쿠키이름, required 는 false 로 선언해야 로그인되지 않은 사용자도 해당 컨트롤러로 진입할 수 있게 된다.
  @GetMapping("/")
    public String homeLogin(@CookieValue(name="memberId",required = false) Long memberId,
    Model model){
    if(memberId == null)
    return "home";

    // 로그인
    Member loginMember = memberRepository.findById(memberId);
    if(loginMember == null)
    return "home";

    model.addAttribute("member",loginMember);

    return "loginHome";
 }

쿠키의 취약점

  1. 쿠키는 웹 브라우저에 개발자모드를 이용하면 언제든지 값을 변경할 수 있다. Cookie의 값을 임의로 변경해서 다른 유저의 정보로 서버로 요청이 가능하다.
  2. 쿠키의 보관된 정보는 웹 브라우저에서 바로 보이므로 보안에 취약하다.

세션(Session)

세션은 쿠키와 다르게 서버에 저장하고 관리하기 때문에 쿠키보다 안전하다.

세션 생성 원리

  • 클라이언트가 Id 와 Password 를 담아서 서버로 요청하면 서버는 Id 와 Password 를 DB에서 조회하고 올바른 사용자면 세션저장소에 sessionId 와 Value 를 저장하고 쿠키에는 sessionId 를 담아서 응답해준다.
  • 쿠키와 다른점이라면 sessionId임의의 식별자를 지정하기 때문에 역추적이 안된다.
  • 클라이언트는 쿠키에 세션ID를 담은채 요청하고 서버는 세션ID를 세션 저장소에서 조회하여 클라이언트를 식별한다.

서블릿 HTTP 세션

Session 은 웹 어플리케이션에서 꼭 필요하므로 서블릿에서 제공하는 HttpSession 을 사용하면 된다.

  • HttpSession 에서는 쿠키 이름을 JSESSIONID 로 지정 되어 있고 Value 에는 추적불가능한 랜덤값인 sessionId가 들어가 있다.
  • getSession() : 이 메서드를 통해 session 을 생성하고 조회한다.
  • 파라미터가 true 라면 session 이 없을때 session 을 생성해준다(디폴트값)
    • 파라미터가 false 이라면 session 이 없어도 session 을 생성하지 않는다.
  • setAttribute() 메서드에는 sessionId 와 value 를 넣는다.
  • invalidate() 메서드는 세션을 제거해준다.
@PostMapping("/login")
public String loginV3(@Valid @ModelAttribute LoginForm form, BindingResult bindingResult, HttpServletRequest request){
    // 로직 생략...
  
    // HttpSession 이용
    // 세션이 있으면 있는 세션 반환, 없으면 신규 세션을 생성해서 반환
    HttpSession session = request.getSession();
    // 세션에 로그인 회원 정보를 보관
    session.setAttribute(SessionConst.LOGIN_MEMBER,loginMember);

    return "redirect:/";
}

@PostMapping("/logout")
public String logoutV3(HttpServletRequest request){
    HttpSession session = request.getSession(false);
    if(session != null)
        session.invalidate();

    return "redirect:/";
}

웹 브라우저의 개발자 모드를 들어가서 Cookies 목록을 보면 쿠키이름에는 HttpSession 이 지원하는 JSESSIONID 가 들어가 있고 Value 에는 서버에서 임의로 지정한 sessionId 가 담겨져 있는걸 확인할 수 있다.

세션 타임아웃

웹 어플리케이션 로직을 짤 때 세션을 끊는 로직은 보통 /logout 같이 웹 브라우저에서 로그아웃 버튼을 누를 때 동작한다, 하지만 일반인들은 웹 브라우저를 끄는 경우가 대부분이다.

  • HTTP 통신은 비 연결성(ConnectionLess) 때문에 서버 입장에서는 클라이언트가 웹 브라우저를 종료했는지 알 수 없다.
  • 세션의 종료 시점은 사용자가 마지막으로 요청한 시간을 기준으로 해야한다.
  • application.yml 에서 세션 타임아웃을 설정할 수 있다.
  server.servlet.session.timeout=1800 #30분
  • 특정 세션에서만 적용할려면 session.setMaxInactiveInterval() 메서드를 사용하면 된다.
profile
백엔드개발자

0개의 댓글