(1) 로그인 처리 - 쿠키

CJY·2023년 4월 2일
0

스프링

목록 보기
8/14

이야기에 앞서 패키지 설계에 대해 알았다.
도메인이 가장 중요하다
도메인이란 화면, UI, 기술 인프라 등의 영역을 제외한 시스템이 구현해야 하는 핵심 비즈니스 업무 영역을 말한다.

도메인 패키지 외에 web이란 패키지를 추가했다. web의 경우 다른 기술로 대체될 수 있다는 점을 인지해야한다. 따라서 도메인 패키지의 내용은 독립적으로 작성되어야 하고 웹이 도메인 코드를 의존하여 만들어지는 것이다. 반대로 말하면 domainweb을 참조하면 안된다.

domain

  • item

  • member

    • member
    • member repository
  • login

    • login service

web

  • item
  • member
    • member controller
  • login
    • login form : 폼 전송 객체
    • login controller

쿠키

기본적으로 HTTP 통신을 하기 때문에 웹은 비연결성 특징이 있다. 그런데 로그인을 한번하고 나면 어떻게 로그인 상태를 유지할까? 쿼리 파라미터를 이용한 URL을 계속 보내야할까? 제목에서 봤듯이 쿠키를 이용하면 될 것 같다.

서버에 로그인으로 인증에 성공하면 HTTP response에 쿠키를 담아 브라우저에 전송한다면 앞으로 브라우저는 request에 해당 쿠키를 계속 보내줄 것이다.

종류

  • 영속 쿠키: 만료 날짜를 입력하면 해당 날짜까지 유지
  • 세션 쿠키: 만료 날짜를 생략하면 브라우저 종료까지만 유지

브라우저를 종료하면 보통 로그아웃 되는 웹을 만들기 때문에 세션 쿠키를 이용하자.

세션 쿠키 생성

@PostMapping("/login")
public String login(@validated @ModelAttribute LoginForm form, BindingResult bindingresult, HttpServletResponse response) {
	검증 처리~
    로그인 서비스로 로그인 확인~
    로그인 성공한다면?
    
    Cookie newCookie = new Cookie("memberId", String.valueOf(member.getId()));
    response.addCookie(newCookie);
    
    리턴
}

우선 member는 입력받은 로그인 정보를 바탕으로 찾은 저장된 회원 인스턴스다. 맵의 key, value처럼 새로운 쿠키를 생성해주고 이를 HttpServletResponseaddCookie로 담아준다. 이러면 웹 브라우저는 종료 전까지 해당 회원의 쿠키값, 여기서는 회원의 id 를 보내준다.

만약 request에 담긴 쿠키값을 받고 싶다면 @CookieValue를 이용하면 된다.

@GetMapping("/")
public String homeLogin(@CookieValue(name = "memberId", required = false) Long memberId, 
				Model model) {
	if (memberId == null) {
    	return "home";
	}

쿠키는 key가 아니라 name이라고 한다. 그리고 뒤에 requiredfalse로 한 이유는 로그인하지 않은 고객들이 해당 URL로 접근할 수 있도록 설정한 것이다.

그럼 사용자가 로그아웃 버튼을 누른다면 가지고 있던 쿠키를 지워줄 필요가 있어 보인다. 지우는 방법은 같은 쿠키 이름을 지정해주는데 쿠키 종료 날짜를 0으로 만드는 것이다.

@PostMapping("/logout")
public String logout(HttpServletResponse response) {
	expireCookie(response, "memberId");
	return "redirect:/";
}
private void expireCookie(HttpServletResponse response, String cookieName) {
	Cookie cookie = new Cookie(cookieName, null);
	cookie.setMaxAge(0);
	response.addCookie(cookie);
}

쿠키 종료 날짜는 쿠키의 메서드인 setMaxAge()를 통해 지정할 수 있다.

문제점

쿠키와 보안 문제

쿠키를 사용해서 로그인Id를 전달해서 로그인을 유지할 수 있었다. 그런데 여기에는 심각한 보안 문제가 있다.
보안 문제

  • 쿠키 값은 임의로 변경할 수 있다.
    클라이언트가 쿠키를 강제로 변경하면 다른 사용자가 된다.
    실제 웹브라우저 개발자모드(F12) Application Cookie 변경이 가능하다.
  • 쿠키에 보관된 정보는 훔쳐갈 수 있다.
    만약 쿠키에 개인정보나, 신용카드 정보가 있다면?
    이 정보가 웹 브라우저에도 보관되고, 네트워크 요청마다 계속 클라이언트에서 서버로 전달된다.
    쿠키의 정보가 나의 로컬 PC에서 털릴 수도 있고, 네트워크 전송 구간에서 털릴 수도 있다.
  • 해커가 쿠키를 한번 훔쳐가면 평생 사용할 수 있다.
    해커가 쿠키를 훔쳐가서 그 쿠키로 악의적인 요청을 계속 시도할 수 있다.

대안

  • 쿠키에 중요한 값을 노출하지 않고, 사용자 별로 예측 불가능한 임의의 토큰(랜덤 값)을 노출하고, 서버에서 토큰과 사용자 id를 매핑해서 인식한다. 그리고 서버에서 토큰을 관리한다.
  • 토큰은 해커가 임의의 값을 넣어도 찾을 수 없도록 예상 불가능 해야 한다.
  • 해커가 토큰을 털어가도 시간이 지나면 사용할 수 없도록 서버에서 해당 토큰의 만료시간을 짧게(예: 30분) 유지한다. 또는 해킹이 의심되는 경우 서버에서 해당 토큰을 강제로 제거하면 된다.

정리

로그인을 유지하는 방법 중 쿠키에 대해 알아보았다. 쿠키 클래스를 이용해 새로운 쿠키를 만들어보고 서블릿이 제공하는 간단한 함수로 쿠키를 추가했다. 뭔가 굉장히 간단한만큼 보안에 있어 심각한 문제들이 보인다. 바로 위에 작성한 대안을 실현하기 위한 방법 중 세션을 다음 시간에 알아보려한다.

profile
열심히 성장 중인 백엔드

0개의 댓글