250x250
Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 코드트리
- DI
- HttpServletResponse
- 코드트리조별과제
- 스프링컨테이너
- ocp
- java
- 오버라이딩
- objecterror
- 인터페이스
- 스프링
- 테스트코드
- 김영한
- 오블완
- 추상클래스
- 티스토리챌린지
- 서블릿
- @configuration
- 싱글톤
- fielderror
- 백준
- 프록시
- http 메시지 컨버터
- equals()
- html form
- 코딩테스트
- JSON
- 참조변수
- 의존관계
- 다형성
Archives
- Today
- Total
minOS
로그인 - 요구사항, 쿠키 사용 본문
728x90
로그인 요구사항
- 홈 화면 - 로그인 전
ㄴ회원 가입
ㄴ로그인
- 홈 화면 - 로그인 후
ㄴ본인 이름(누구님 환영합니다.)
ㄴ상품 관리
ㄴ로그 아웃
- 보안 요구사항
ㄴ로그인 사용자만 상품에 접근하고, 관리할 수 있음
ㄴ로그인 하지 않은 사용자가 상품 관리에 접근하면 로그인 화면으로 이동
- 회원 가입, 상품 관리
로그인 - 쿠키 사용
쿼리 파라미터를 계속 유지하면서 보내는 것은 매우 어렵고 번거로운 작업이다. 쿠키를 사용해보자.
쿠키
서버에서 로그인에 성공하면 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` 데이터도 모델에 담아서 전달한다.
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="utf-8"> <link th:href="@{/css/bootstrap.min.css}" href="../css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="container" style="max-width: 600px"> <div class="py-5 text-center"> <h2>홈 화면</h2> </div> <h4 class="mb-3" th:text="|로그인: ${member.name}|">로그인 사용자 이름</h4> <hr class="my-4"> <div class="row"> <div class="col"> <button class="w-100 btn btn-secondary btn-lg" type="button" th:onclick="|location.href='@{/items}'|"> 상품 관리 </button> </div> <div class="col"> <form th:action="@{/logout}" method="post"> <button class="w-100 btn btn-dark btn-lg" type="submit"> 로그아웃 </button> </form> </div> </div> <hr class="my-4"> </div> <!-- /container --> </body> </html> ```
- th:text="|로그인: ${member.name}|"` :로그인에성공한사용자이름을출력한다.
- 상품 관리, 로그아웃 버튼을 노출한다.
로그인 이후 웰컴 페이지 접근 실행
로그인에 성공하면 사용자 이름이 출력되면서 상품 관리, 로그아웃 버튼을 확인할 수 있다. 로그인에 성공시 세션 쿠키 가 지속해서 유지되고, 웹 브라우저에서 서버에 요청시 `memberId` 쿠키를 계속 보내준다
로그아웃 기능
로그아웃 방법
- 세션 쿠키이므로 웹 브라우저 종료시
- 서버에서 해당 쿠키의 종료 날짜를 0으로 지정
@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); }
실행
로그아웃도 응답 쿠키를 생성하는데 `Max-Age=0` 를 확인할 수 있다. 해당 쿠키는 즉시 종료된다.
쿠키와 보안 문제
쿠키를 사용해서 `memberId` 를 전달해서 로그인을 유지할 수 있었다. 그런데 여기에는 심각한 보안 문제가 있다.
보안 문제
1) 쿠키 값은 임의로 변경할 수 있다.
ㄴ클라이언트가 쿠키를 강제로 변경하면 다른 사용자가 된다.
ㄴ 실제 웹브라우저 개발자모드 Application Cookie 변경으로 확인
ex) `Cookie: memberId=1` `Cookie: memberId=2` (다른사용자의이름이보임)
2) 쿠키에 보관된 정보는 훔쳐갈 수 있다.
ㄴ만약 쿠키에 개인정보나, 신용카드 정보가 있다면 이 정보가 웹 브라우저에도 보관되고, 네트워크 요청마다 계속 클라이언트에 서 서버로 전달된다.
ㄴ쿠키의 정보가 나의 로컬 PC에서 털릴 수도 있고, 네트워크 전송 구간에서 털릴 수도 있다.
3) 해커가 쿠키를 한번 훔쳐가면 평생 사용할 수 있다.
ㄴ해커가 쿠키를 훔쳐가서 그 쿠키로 악의적인 요청을 계속 시도할 수 있다.
대안
1) 쿠키에 중요한 값을 노출하지 않고, 사용자 별로 예측 불가능한 임의의 토큰(랜덤 값)을 노출하고, 서버에서 토큰과 사용자 id를 매핑해서 인식한다. 그리고 서버에서 토큰을 관리한다.
2) 토큰은 해커가 임의의 값을 넣어도 찾을 수 없도록 예상 불가능 해야 한다.
3)해커가 토큰을 털어가도 시간이 지나면 사용할 수 없도록 서버에서 해당 토큰의 만료시간을 짧게(예: 30분) 유지 한다. 또는 해킹이 의심되는 경우 서버에서 해당 토큰을 강제로 제거하면 된다.
728x90
'TIL > 김영한의 스프링 MVC 2편 - 백엔드 웹 개발 핵심 기술' 카테고리의 다른 글
로그인 처리하기1 - 서블릿 HTTP 세션1, 서블릿 HTTP 세션2,세션 정보와 타임아웃 설정 (1) | 2024.09.24 |
---|---|
로그인 처리하기1 - 세션 동작 방식 , 세션 만들기, 세션 적용 (0) | 2024.09.24 |
Bean Validation - groups,Form 전송 객체 분리, HTTP 메시지 컨버터 (2) | 2024.09.18 |
Bean Validation - 오브젝트 오류,수정에 적용,한계 (0) | 2024.09.18 |
Bean Validation - Bean Validation 애노테이션 적용,스프링 적용,에러 코드 (0) | 2024.09.18 |