[Spring] 로그인(쿠키, 세션)

dh·2022년 8월 15일
2

인증(Authentication)

목록 보기
1/5
post-thumbnail

Cookie

  • 서버에서 사용자의 컴퓨터에 저장하는 정보파일
  • 사용자가 별도의 요청을 하지 않아도 브라우저는 request시 Request Header에 넣어 자동으로 서버에 전송
  • key와 value로 구성되고 String형태로 이루어져 있음
  • Browser마다 저장되는 쿠키는 다르다.(서버에서는 Brower가 다르면 다른 사용자로 인식)

Cookie의 사용목적

  • 세션관리 : 사용자 ID, 접속시간, 장바구니 등의 서버가 알아야 할 정보 저장.
  • 개인화 : 사용자마다 다르게 그 사람에 적절한 페이지를 보여줄 수 있다.
  • 트래킹 : 사용자의 행동과 패턴을 분석하고 기록.

Cookie의 사용 예

  • ID저장(자동로그인)
  • 일주일간 다시 보지 않기
  • 최근 검색한 상품들을 광고에 추천
  • 쇼핑몰 장바구니 기능

Cookie의 구성요소

  • 이름 : 여러 개의 쿠키가 client의 컴퓨터에 저장되므로 각 쿠키를 구별하는데 사용되는 이름
  • 값 : 쿠키의 이름과 매핑되는 값
  • 유효기간 : 쿠키의 유효기간
  • 도메인 : 쿠키를 전송할 도메인
  • 경로 : 쿠키를 전송할 요청 경로

Cookie의 동작 순서



  • client가 페이지를 요청
  • WAS는 Cookie를 생성
  • HTTP헤더에 Cookie를 넣어 응답
  • 브라우저는 넘겨받은 Cookie를 PC에 저장하고, 다시 요청시 Cookie를 함께 전송
  • 브라우저가 종료되도 Cookie의 만료 기간이 남아 있다면 Client는 계속 보관.
  • 동일 사이트 재방문시 Client의 PC에 해당 Cookie가 있는 경우, 요청과 함께 Cookie를 전송

Cookie의 특징

  • 이름, 값, 만료일(저장 기간 설정), 경로 정보로 구성되어 있다.
  • 클라이언트에 총 50~180개의 쿠키를 저장 가능(브라우저별 차이)
  • 하나의 도메인 당 20개의 쿠키를 가질 수 있다.
  • 하나의 쿠키는 4KB(4096byte)까지 저장 가능.

Cookie의 주요 기능

기능method
생성Cookie cookie = new Cookie(String name, String value)
값 변경/ 얻기cookie.setValue(String value) / String value = cookie.getValue()
사용 도메인지정/ 얻기cookie.setDomain(String domain) / String domain = cookie.getDomain()
값 범위지정/ 얻기cookie.setPath(String path) / String path = cookie.getPath()
유효기간/ 얻기cookie.setMaxAge(int expiry) / int expiry = cookie.getMaxAge()
쿠키 삭제cookie.setMaxAge(0)
쿠키 전송response.addCookie(cookie)
쿠키값 얻기Cookie cookies[] = request.getCookies()

Cookie를 이용한 로그인/로그아웃 처리 코드

LoginService

@Service
@RequiredArgsConstructor
public class LoginService{

	private final MemberRepository memberRepository;

	public Member login(String loginId, String password){
    	return memberRepository.findByLoginId(loginId)
			.filter(m -> m.getPassword().equals(password)
            .orElse(null);
    }
}

LoginController

@Slf4j
@Controller
@RequiredArgsConstructor
public class LoginController {

    private final LoginService loginService;

    @GetMapping("/login")
    public String loginForm(@ModelAttribute("loginForm") LoginForm form){
        return "login/loginForm";
    }

    @PostMapping("/login")
    public String login(@Valid @ModelAttribute("loginForm") LoginForm form, BindingResult bindingResult, HttpServletResponse response){
        if(bindingResult.hasErrors()){
            return "login/loginForm";
        }

        Member loginMember = loginService.login(form.getLoginId(), form.getPassword());

        if(loginMember == null){
            bindingResult.reject("loginFail", "아이디 또는 비밀번호가 맞지 않습니다.");
            return "login/loginForm";
        }

        //로그인 성공 처리
        //쿠키에 시간 정보를 주지 않으면 세션 쿠키(브라우저 종료시 모두 종료)
        Cookie idCookie = new Cookie("memberId", String.valueOf(loginMember.getId()));
        response.addCookie(idCookie);
        return "redirect:/";
    }
    
    @PostMapping("/logout")
    public String logout(HttpServletResponse response){
        expireCookie(response, "memberId");
        return "redirect:/";
    }
    
    private static void expireCookie(HttpServletResponse response, String cookieName) {
        Cookie cookie = new Cookie(cookieName, null);
        cookie.setMaxAge(0);
        response.addCookie(cookie);
    }
}

결과

로그인성공시 서버에서 쿠키를 생성하고 HTTP헤더에 넣어 응답하는 것을 확인할 수 있다.

새로고침후 클라이언트가 다음 요청할 때 쿠키를 함께 보내는것을 확인할 수 있다

Cookie의 보안 문제점

  • Cookie값은 임의로 변경할 수 있다
    개발자모드의 Application에서 Cookie의 값을 임의로 변경하고 새로고침을 해보면 다른 회원의 정보가 보이는걸 확인할 수 있음..

  • 쿠키에 보관된 정보는 털릴 수 있음
    • 만약 쿠키에 중요한 정보가 있다면, 이정보가 브라우저에도 보관되고 네트워크 요청마다 계속 서버로 전달된다.(이 과정에서 쿠키정보가 털릴 수 있음)
  • 해커가 쿠키를 훔쳐가서 악의적인 요청을 계속 시도할 수 있다.

대안

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

Session

  • 방문자가 웹 서버에 접속해 있는 상태를 하나의 단위로 보고 그것을 세션이라 한다.
  • WAS의 memory에 Object의 형태로 저장
  • memory가 허용하는 용량까지 헤나 없이 저장 가능

session의 사용 예

  • site내에서 화면을 이동해도 로그인이 풀리지 않고 유지
  • 장바구니

session의 동작 순서



  • 클라이언트가 페이지를 요청
  • 서버는 접근한 클라이언트의 Request-Header의 필드인 Cookie를 확인하여, 클라이언트가 해당 session-id를 보냈는지 확인.
  • session-id가 존재하지 않는다면, 서버는 쿠키 이름이 JSESSIONID이고 값은 추정 불가능한 랜덤 값의 쿠키를 생성해 서버에 저장
  • 클라이언트는 재접속시, 이 쿠키(JSESSIONID)를 이용하여 session-id값을 서버에 전달

session의 특징

  • 웹 서버에 웹컨테이너의 상태를 유지하기 위한 정보를 저장.
  • 웹 서버에 저장되는 쿠키(=세션 쿠키)
  • 브라우저를 닫거나, 서버에서 세션을 삭제 했을 때만 삭제가 되므로, 쿠키보다 비교적 보안이 좋다.
  • 저장 데이터에 제한이 없다.
  • 각 클라이언트 고유 Session ID를 부여한다.
  • Session ID로 클라이언트를 구분하여 각 클라이언트 요구에 맞는 서비스 제공.

session의 주요 기능

기능method
생성HttpSession session = request.getSession()
값 저장session.setAttribute(String name, Object value)
값 얻기Object obj = session.getAttribute(String name)
값 제거session.removeAttribute(String name) 특정이름의 속성제거,
session.invalidate() binding되어 있는 모든 속성제거
유효기간/ 얻기cookie.setMaxAge(int expiry) / int expiry = cookie.getMaxAge()
생성시간long ct = session.getCreationTime()
마지막 접근 시간long lat = session.getLastAccessedTime()

Cookie를 이용한 로그인/로그아웃 처리 코드

LoginController

    @PostMapping("/login")
    public String login3(@Valid @ModelAttribute("loginForm") LoginForm form, BindingResult bindingResult, HttpServletRequest request){
        if(bindingResult.hasErrors()){
            return "login/loginForm";
        }

        Member loginMember = loginService.login(form.getLoginId(), form.getPassword());

        if(loginMember == null){
            bindingResult.reject("loginFail", "아이디 또는 비밀번호가 맞지 않습니다.");
            return "login/loginForm";
        }

        //로그인 성공 처리
        //세션이 있으면 있는 세션 반환, 없으면 신규 세션을 생성
        HttpSession session = request.getSession();
        //세션에 로그인 회원 정보 보관
        session.setAttribute("loginMember", loginMember);

        return "redirect:/";
    }
    
    @PostMapping("/logout")
    public String logout3(HttpServletRequest request){
        HttpSession session = request.getSession(false);
        if(session!=null){
            session.invalidate();
        }
        return "redirect:/";
    }

결과

로그인성공 시 서버에서 쿠키 이름이 JSESSIONID이고 값은 추정 불가능한 랜덤 값의 쿠키를 생성하여 응답한다.

새로고침후 클라이언트가 다음 요청할 때 세션이 만든 쿠키를 함께 보내는것을 확인할 수 있다

session 정리

  • 쿠키 값 변조 가능 -> 예상 불가능한 복잡한 세션ID를 사용
  • 쿠키에 보관하는 정보는 털릴 가능성이 있음 -> 세션ID가 털려도 여기에는 중요한 정보가 없음
  • 쿠키 탈취 후 사용 -> 해커가 토큰을 털어가도 시간이 지나면 사용 못하게 짧게(30분)유지. 또는 해킹 의심시 서버에서 해당 세션을 강제로 제거.

0개의 댓글