쿠키, 세션

최주영·2024년 2월 23일
0

springboot

목록 보기
9/13

✅ 쿠키

  • cookie
    ->영속쿠키 : 만료 날짜를 입력하면 해당 날짜까지 유지
    ->세션쿠키 : 만료 날짜를 생략하면 브라우저 종료시까지만 유지
    -> client(사용자) 컴퓨터에 필요한 데이터를 저장하고 서버이용시에 가져오는 구조
    -> 객체저장 불가능, 문자열만 저장 가능, 크기에 제한 O,
    -> 보안에 필요하지않는 데이터들을 쿠기에넣음 ex) 아이디 저장, 최근본상품

  • 공통점 : 둘 다 저장구조는 key:value 형식임


✅ 쿠키 생성

@PostMapping("/login")
public String login(@ModelAttribute LoginForm form, HttpServletResponse response){
	
    // 쿠키에 시간 정보를 주지 않으면 세션 쿠키됨 (브라우저 종료시 모두 종료)
    Cookie idCookie = new Cookie("memberId", String.valueOf(loginMember.getId())):
    response.addCookie(idCookie); // 브라우저에 쿠키 저장
    
    return "redirect"/";
}


✅ 쿠키 값 어노테이션 활용

  • @CookieValue
@GetMapping("/")
public String homeLogin(@CookieValue(name = "memberId", required = false) Long memberId, Model model){
	
    if(memberId == null){ // 쿠키값이 null이면
    	return "home";  // 해당 뷰파일로 이동
    }
	
    // 로그인
    Member loginMember = memberRepository.findById(memberId);
    if(loginMember == null){ // 로그인 실패할때
    	reutrn "home";
    }
    
    model.addAttribute("member",loginMember);
    return "loginHome"; // 로그인 성공시 해당 뷰파일로 이동    
}
  • 쿠키로 로그아웃 하기 = 쿠키 삭제
    -> 삭제할 쿠키와 동일한 key의 cookie 객체를 생성하고
    -> setMaxAge(0)으로 설정
@PostMapping("/logout")
public String logout(HttpServletResponse response){
	Cookie cookie = new Cookie(memberId, null);
    cookie.setMaxAge(0);
    response.addCookie(cookie);
    return "redirect:/";

💡 하지만 쿠키로 로그인 유지를 한다면 보안에서 큰 문제가 생긴다
(위 코드로 로그인 유지 기능 하면 큰일남)

  • 개발자 도구에서 쿠키값을 강제로 변경 하면 다른사용자의 정보로 바뀐다
    개발자도구 -> Application -> Cookie 변경으로 확인

  • 쿠키에 보관된 정보를 훔쳐갈 수 있다
    쿠키에 개인정보나, 신용카드 정보가 있다면?
    쿠키의 정보가 나의 로컬 pc와 네트워크 전송 구간에서 털릴 수 있다

  • 해커가 쿠키를 한번 훔쳐가면 평생 사용할 수 있다
    해커가 쿠키를 훔쳐가서 그 쿠키로 악의적인 요청을 계속 시도할 수 있다

  • 해결방안
    쿠키에 중요한 값을 노출하지 않고, 사용자 별로 예측 불가능한 임의의 토큰(랜덤)값을 노출
    서버에서 토큰과 사용자 id를 매핑해서 인식하며 서버에서 토큰을 관리한다
    토큰의 만료 시간을 짧게 설정한다 (ex 30분)

다른 방법으로 세션이라는 것을 사용하면 된다


✅ 세션

  • session
    -> 서버 컴퓨터에 저장됨, 객체 저장 가능, 크기 제한 x, 보안이 필요한 데이터들은 세션에 넣음

서블리 기반으로 세션 만들기

// 상수로 하나 정의하기 (클래스 하나 만들기)
 public class SessionConst{
 	public static final String LOGIN_MEMBER = "loginMember";
 }
// LoginController
@PostMapping("/login") // 로그인
public String login(@ModelAttribute LoginForm form, HttpServletRequest request){

Member loginMember = loginService.login(form.getLoginId(), form.getPassword()):
if(loginMember == null){
	return "login/loginForm"; // 로그인실패시 다시 로그인입력창으로 이동
}

  // 로그인 성공처리 후 
  // 세션이 있으면 있는 세션 반환, 없으면 신규 세션을 생성
  HttpSession session = request.getSession(true);
  //getSession 메소드에 boolean형으로 매개변수를 설정할 수 있다. (기본값 = true)
  // request.getSession(true) -> 세션이 있으면 기존 세션 반환, 세션이 없으면 새로운 세션 생성해서 반환
  // request.getSession(false) -> 세션이 있으면 기존 세션 반환, 세션이 없으면 새로운 세션 생성 x
  
  
  //session.setMaxInactiveInterval(5); // 이 활동에서만 세션 활동이 5초동안 없으면 세션삭제
  
  // 세션에 로그인 회원 정보 보관
  session.setAtrribute(SessionConst.LOGIN_MEMBER, loginMember); // = setAttribute("loginMember", loginMember);

  return "redirect"/";
}

@PostMapping("logout") //로그아웃
public String logout(HttpServletRequest request){
	HttpSession session = request.getSession(false); // true로 하면 새로 만들어버리기때문에 기존에 있는것을 갖고오기 위해서 false 사용
    
    if(session != null){
    	session.invalidate(); // 세션삭제
    }
    return "redirect:/";
}
// 홈 화면 (redirect:/"로 왔기때문에)
@GetMapping("/")
public String homeLogin(HttpServletRequest request, Model model){
	HttpSession session = request.getSession(false); // 현재 세션이 있는지 확인
    if(session == null){
    	return "home"; // 세션이 없으면 로그인되지 않은 홈 view로 이동
    }
    
    Member loginMember = session.getAttribute(SessionConst.LOGIN_MEMBER); // 세션갖고옴
    
    // 세션에 회원 데이터가 없으면 home view로 이동
    if(loginMember == null){
    	return "home";
    }
    
    // 세션이 유지되면 로그인된 home view로 이동
    model.addAttribute("member",loginMember);
    return "loginHome";
}

Spring 에서 제공하는 방법으로 세션 만들기

  • 아래 @GetMapping("/") 부분만 빼고, 나머지는 위 서블릿 기반에서 했던 코드와 동일
  • @SessionAttribute -> 세션 체크해서 갖고옴
@GetMapping("/")
public String homeLogin(
	@SessionAttribute(name = SessionConst.LOGIN_MEMBER, required = false) Member loginMember, Model, model){
    
    // 세션에 회원 데이터가 없으면 home view로 이동
    if(loginMember == null){
    	return "home";
    }
    
    // 세션이 유지되면 로그인된 home view로 이동
    model.addAttribute("member",loginMember);
    return "loginHome";
}

💡 참고


✅ 세션 타임아웃 설정

세션은 사용자가 로그아웃을 직접 호출해서 session.invalidate() 가 호출되는 경우 삭제된다.
하지만 대부분 사용자는 로그아웃을 호출하지 않고, 단순히 웹 브라우저를 종료한다
문제점은 HTTP가 비 연결성임
-> 서버 입장에서는 해당 사용자가 웹 브라우저를 종료한 것인지 아닌지 인식 불가능 함

  • 문제점 발생
    세션과 관련된 쿠키(JSESSIONID)를 탈취 당했을 때, 시간이 지나도 해당 쿠키로 악의적 요청 가능
    세션은 기본적으로 메모리가 생성되는데, 메모리 크기가 무한하지 않기때문에 필요할때만 사용해야함
    EX) 10만명의 사용자가 로그인하면, 10만개의 세션이 생성됨

  • 해결 방안
    사용자가 서버에 최근에 요청한 시간을 기준으로 30분 유지 (시간은 변경할 수 있음)
    (사용자가 서비스를 이용하면 30분으로 다시 늘어남) -> HttpSession 은 이 방식을 사용하고있음
    사용자가 30분동안 아무것도 하지 않으면 세션이 끊김

  • 세션 타임아웃 설정
    스프링 부트에서 application.properties 또는 application.yml 에 설정
// properties 파일
server.servlet.session.timeout=1800 // 1800 = (30분)
# yml 파일
server:  
	servlet:   
    	session:      
        	timeout: 1800
  • 특정 세션 단위로 시간 설정
    -> setMaxInactiveInterval 메소드 사용
HttpSession session = request.getSession(true);
session.setMaxInactiveInterval(1800); //1800초 설정
  • 주의할점
    실무에서는 세션에 최소한의 데이터를 보관해야한다 -> 메모리 사용량 급격하게 늘어나면 장애 발생
    즉 모든 필드가 들어있는 객체를 세션에 넣지말고
    필요한 정보들만 들어있는 객체를 생성해서 세션에 넣기 (ex 유저 아이디와, 유저 이름만)
    메모리 사용량 = 보관한 데이터 용량 * 사용자 수

profile
우측 상단 햇님모양 클릭하셔서 무조건 야간모드로 봐주세요!!

0개의 댓글