- 홈 화면 - 로그인 전 ㄴ회원 가입 ㄴ로그인 - 홈 화면 - 로그인 후 ㄴ본인 이름(누구님 환영합니다.) ㄴ상품 관리 ㄴ로그 아웃 - 보안 요구사항 ㄴ로그인 사용자만 상품에 접근하고, 관리할 수 있음 ㄴ로그인 하지 않은 사용자가 상품 관리에 접근하면 로그인 화면으로 이동 - 회원 가입, 상품 관리
로그인 - 쿠키 사용
쿼리 파라미터를 계속 유지하면서 보내는 것은 매우 어렵고 번거로운 작업이다. 쿠키를 사용해보자.
쿠키
서버에서 로그인에 성공하면 HTTP 응답에 쿠키를 담아서 브라우저에 전달하자. 그러면 브라우저는 앞으로 해당 쿠키를 지속해서 보내준다.
쿠키 종류 - 영속 쿠키: 만료 날짜를 입력하면 해당 날짜까지 유지 - 세션 쿠키: 만료 날짜를 생략하면 브라우저 종료시 까지만 유지
쿠키 생성 - 쿠키 로그인
@PostMapping("/login")
public String login(@Validated @ModelAttribute LoginForm loginForm , BindingResult bindingResult, HttpServletResponse response){
if(bindingResult.hasErrors()){
return "login/loginForm";
}
Member loginMember = loginService.login(loginForm.getLoginId(), loginForm.getPassword());
if (loginMember == null){
bindingResult.reject("loginFail","아이디 또는 비밀번호가 맞지 않습니다.");
return "login/loginForm";
}
//로그인 성공 처리 TODO -> 쿠키 만들어서 클라이언트에게 전달
Cookie idCookie = new Cookie("memberId",String.valueOf(loginMember.getId()));
response.addCookie(idCookie); // 쿠키에 시간 정보를 주지 않으면 세션 쿠키 (브라우저 종료시 모두 종료)
return "redirect:/";
}
로그인에 성공하면 쿠키를 생성하고 `HttpServletResponse` 에 담는다. 쿠키 이름은 `memberId` 이고, 값은 회원의 `id` 를 담아둔다. 웹 브라우저는 종료 전까지 회원의 `id` 를 서버에 계속 보내줄 것이다.
클라이언트 쿠키 전달1 - 로그인 이후 웰컴 페이지 접근
@GetMapping("/") //required = false -> 로그인하지 않은 사용자도 허용(쿠키값 없는)
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";
}
- @CookieValue` 를 사용하면 편리하게 쿠키를 조회할 수 있다. - 로그인 하지 않은 사용자도 홈에 접근할 수 있기 때문에 required = false를 사용한다.
로직 분석 - 로그인 쿠키( `memberId` )가 없는 사용자는 기존 `home` 으로 보낸다. 추가로 로그인 쿠키가 있어도 회원이 없으면 `home` 으로 보낸다. - 로그인 쿠키( `memberId` )가 있는 사용자는 로그인 사용자 전용 홈 화면인 `loginHome` 으로 보낸다. 추가로 홈 화면에 화원 관련 정보도 출력해야 해서 `member` 데이터도 모델에 담아서 전달한다.
실행 로그아웃도 응답 쿠키를 생성하는데 `Max-Age=0` 를 확인할 수 있다. 해당 쿠키는 즉시 종료된다.
쿠키와 보안 문제
쿠키를 사용해서 `memberId` 를 전달해서 로그인을 유지할 수 있었다. 그런데 여기에는 심각한 보안 문제가 있다.
보안 문제
1) 쿠키 값은 임의로 변경할 수 있다. ㄴ클라이언트가 쿠키를 강제로 변경하면 다른 사용자가 된다. ㄴ 실제 웹브라우저 개발자모드 Application Cookie 변경으로 확인 ex) `Cookie: memberId=1` `Cookie: memberId=2` (다른사용자의이름이보임)
2) 쿠키에 보관된 정보는 훔쳐갈 수 있다. ㄴ만약 쿠키에 개인정보나, 신용카드 정보가 있다면 이 정보가 웹 브라우저에도 보관되고, 네트워크 요청마다 계속 클라이언트에 서 서버로 전달된다. ㄴ쿠키의 정보가 나의 로컬 PC에서 털릴 수도 있고, 네트워크 전송 구간에서 털릴 수도 있다.
3) 해커가 쿠키를 한번 훔쳐가면 평생 사용할 수 있다. ㄴ해커가 쿠키를 훔쳐가서 그 쿠키로 악의적인 요청을 계속 시도할 수 있다.
대안
1) 쿠키에 중요한 값을 노출하지 않고, 사용자 별로 예측 불가능한 임의의 토큰(랜덤 값)을 노출하고, 서버에서 토큰과 사용자 id를 매핑해서 인식한다. 그리고 서버에서 토큰을 관리한다. 2) 토큰은 해커가 임의의 값을 넣어도 찾을 수 없도록 예상 불가능 해야 한다. 3)해커가 토큰을 털어가도 시간이 지나면 사용할 수 없도록 서버에서 해당 토큰의 만료시간을 짧게(예: 30분) 유지 한다. 또는 해킹이 의심되는 경우 서버에서 해당 토큰을 강제로 제거하면 된다.