Written by
Sunwoo Han
on
on
로그인 처리 - 쿠키, 세션
스프링 MVC 2편 - 백엔드 웹 개발 활용 기술을 공부하고 정리하는 포스트입니다.
로그인 처리
- 로그인의 핵심 비즈니스 로직
- 회원을 조회한 다음 파라미터로 넘어온 password와 비교
→ 같으면 회원을 반환, 다르면null
을 반환
- 회원을 조회한 다음 파라미터로 넘어온 password와 비교
로그인 처리하기 - 쿠키 사용
로그인 상태 유지하기
- 쿼리 파라미터를 계속 유지하면서 보내는 것은 매우 어렵고 번거로운 작업
-
서버에서 로그인에 성공하면 HTTP 응답에 쿠키를 담아서 브라우저에 전달 → 브라우저가 해당 쿠키를 지속해서 전송
- 쿠키 생성
- 클라이언트 쿠키 전달
- 쿠키에는 영속 쿠키와 세션 쿠키가 존재
- 영속 쿠키 : 만료 날짜를 입력하면 해당 날짜까지 유지
- 세션 쿠키 : 만료 날짜를 생략하면 브라우저 종료 시 까지만 유지
세션 쿠키 생성
Cookie idCookie = new Cookie("memberId", String.valueOf(loginMember.getId()));
response.addCookie(idCookie);
- 로그인 성공 시 쿠키를 생성하고
HttpServletResponse
에 담음
로그아웃 기능
- 로그아웃 방법
- 세션 쿠키이르모 웹 브라우저 종료 시
- 서버에서 해당 쿠키의 종료 날짜를 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);
}
쿠키와 보안 문제
보안 문제
- 쿠키 값은 임의로 변경 가능
- 클라이언트가 쿠키를 강제로 변경하면 다른 사용자가 됨
- 웹 브라우저에서 개발자모드 → Application → Cookie 변경
- 쿠키에 보관된 정보는 훔쳐갈 수 있음
- 쿠키에 개인정보나 신용카드 정보가 있다면?
→ 이 정보가 웹 브라우저에도 보관되고, 네트워크 요청마다 계속 클라이언트에서 서버로 전다룀 - 쿠키의 정보가 로컬 PC에서 털릴 수도 있고, 네트워크 전송 구간에서 털릴 수도 있음
- 쿠키에 개인정보나 신용카드 정보가 있다면?
- 쿠키를 한 번 훔쳐가면 평생 사용 가능
- 해커가 쿠키를 훔쳐가서 그 쿠키로 악의적인 요청을 계속 시도할 수 있음
대안
- 쿠키에 중요한 값을 노출하지 않아야 함
- 사용자 별로 예측 불가능한 임의의 토큰(랜덤 값)을 출력
- 서버에서 토큰과 사용자 id를 매핑해서 인식하도록 구성 → 서버에서 토큰을 관리
- 토큰은 임의의 값을 넣어도 찾을 수 없도록 구성해야 함
- 서버에서 해당 토큰의 만료시간을 짧게(약 30분) 유지. 해킹이 의심되는 경우 해당 토큰을 강제로 제거
로그인 처리하기 - 세션 동작 방식
-
세션은 쿠키를 사용하지만, 서버에서 데이터를 유지하는 방법
- 세션 생성
- sessionId 생성(임의의 추정 불가능한 랜덤 값)
- 세션 저장소에 sessionId와 보관할 값 저장
- sessionId로 응답 쿠키를 생성해서 클라이언트에 전달
- 세션 조회
- 클라이언트가 요청한 sessionId 쿠키의 값으로 저장소에 보관한 값 조회
- 세션 만료
- 클라이언트가 요청한 sessionId 쿠키의 값으로 저장소에 보관한 sessionId와 값 제거
로그인 처리하기 - 서블릿 HTTP 세션
- 서블릿에서 세션을 위해
HttpSession
이라는 기능을 제공- 서블릿을 통해
HttpSession
을 생성하면JSESSIONID
라는 추정 불가능한 랜덤 값을 가지는 쿠키를 생성함
- 서블릿을 통해
세션 생성과 조회
- 세션을 생성할 때
request.getSession(true)
를 사용하면 됨
public HttpSession getSession(boolean create);
- 세션의
create
옵션request.getSession(true)
- 세션이 있으면 기존 세션을 반환
- 세션이 없으면 새로운 세션을 생성해서 반환
request.getSession(false)
- 세션이 있으면 기존 세션을 반환
- 세션이 없으면 세션을 생성하지 않고
null
을 반환
request.getSession()
: true와 동일
로그인 회원 정보 보관
session.setAttribute(SessionConst.LOGIN_MEMBER, loginMember)
- 세션에 데이터를 보관하는 방식은
request.setAttribute(...)
와 비슷 - 하나의 세션에 여러 값 저장 가능
- 세션에 데이터를 보관하는 방식은
@SessionAttribute
- 스프링에서 지원 → 로그인 된 사용자를 찾을 때 사용
- 세션을 생성하지 않음
TrackingModes
- 웹 브라우저가 쿠키를 지원하지 않을 때 쿠키 대신 URL을 통해서 세션을 유지하는 방법
- URL에 값을 계속 포함해서 전달
- 타임리프 같은 템플릿은 엔진을 통해서 링크를 걸면
jsessionid
를 URL에 자동으로 포함 -
서버 입장에서 웹 브라우저가 쿠키를 지원하는지 하지 않는지 최초에는 판단하지 못하므로, 쿠키 값도 전달하고, URL에
jsessionid
도 함께 전달 - URL 전달 방식을 끄고 항상 쿠키를 통해서만 세션을 유지하고 싶으면 다음 옵션을 사용
server.servlet.session.tracking-modes=cookie
세션 정보와 타임아웃 설정
- sessionId : 세션Id,
JSESSIONID
의 값이다. 예) 34B14F008AA3527C9F8ED620EFD7A4E1 - maxInactiveInterval : 세션의 유효 시간. 예) 1800초
- creationTime : 세션 생성일시
- lastAccessedTime : 세션과 연결된 사용자가 최근에 서버에 접근한 시간, 클라이언트에서 서버로
sessionId
(JSESSIONID
)를 요청한 경우에 갱신 - isNew : 새로 생성된 세션인지, 아니면 이미 과거에 만들어졌고, 클라이언트에서 서버로
sessionId
(JSESSIONID
)를 요청해서 조회된 세션인지 확인
세션 타임아웃 설정
- 세션은 사용자가 로그아웃을 직접 호출해서
session.invalidate()
가 호출 되는 경우 삭제됨- 대부분의 사용자는 브라우저를 종료
- 서버 입장에서는 인식할 수 없음
- 남아있는 세션을 무한정 보관 시
- 세션과 관련된 쿠키(
JSESSIONID
)를 탈취 당했을 경우 오랜 시간이 지나도 해당 쿠키로 악의적인 요청을 할 수 있음 - 세션은 기본적으로 메모리에 생성하기 때문에 꼭 필요한 경우만 생성해서 사용하는게 좋음
- 세션과 관련된 쿠키(
세션 종료 시점
- 세션 생성 시점으로부터 약 30분
- 더 좋은 대안은 생성 시점이 아닌 사용자가 서버에 최근 요청한 시간을 기준으로 약 30분 간 유지
스프링 부트로 글로벌 설정
- 기본 설정 : 60초
server.servlet.session.timeout=60
- 특정 세션 단위로 시간 설정
session.setMaxInactiveInterval(1800); //1800초
세션 타임아웃 발생
- 세션의 타임아웃 시간은 해당 세션과 관련된
JSESSIONID
를 전달하는 HTTP 요청이 있으면 현재 시간으로 다시 초기화 됨session.getLastAccessedTime()
: 최근 세션 접근 시간LastAccessedTime
이후로 timeout 시간이 지나면, WAS가 내부에서 해당 세션을 제거
Comments
SPRING 의 다른 글
-
스프링 타입 컨터버 24 Jun 2022
-
API 예외 처리 17 Jun 2022
-
예외 처리와 오류 페이지 12 Jun 2022
-
로그인 처리 - 인터셉터 08 Jun 2022
-
로그인 처리 - 필터 06 Jun 2022
-
로그인 처리 - 쿠키, 세션 31 May 2022
-
Bean Validation 22 May 2022
-
검증 22 May 2022
-
메시지, 국제화 21 May 2022
-
타임리프 - 스프링 통합과 폼 19 May 2022
-
타임리프 - 기본 기능 10 May 2022
-
스프링 MVC 기본 기능 - 웹 페이지 만들기 02 May 2022
-
스프링 MVC 기본 기능 - HTTP 응답 30 Apr 2022
-
스프링 MVC 기본 기능 - HTTP 요청 24 Apr 2022
-
스프링 MVC 기본 기능 - 요청 매핑 19 Apr 2022
-
스프링 MVC 기본 기능 19 Apr 2022
-
스프링 MVC 구조 이해 14 Apr 2022
-
MVC 프레임워크 만들기 - V4, V5 12 Apr 2022
-
MVC 프레임워크 만들기 - V1, V2, V3 09 Apr 2022
-
서블릿, JSP, MVC 패턴 05 Apr 2022
-
서블릿 29 Mar 2022
-
웹 애플리케이션 이해 24 Mar 2022
-
스프링 웹 계층이란? 05 Nov 2021
-
스프링 시큐리티 공식문서 번역 27 Sep 2021
-
스프링 AOP 총정리 : 개념, 프록시 기반 AOP, @AOP 27 Apr 2021
-
SpEL (스프링 Expression Language) 25 Apr 2021
-
데이터 바인딩 추상화 : Converter와 Formatter 21 Apr 2021
-
데이터 바인딩 추상화 : PropertyEditor 12 Apr 2021
-
Validation 추상화 10 Apr 2021
-
Resource 추상화 08 Apr 2021
-
IoC 컨테이너 9부 07 Apr 2021
-
IoC 컨테이너 8부 06 Apr 2021
-
IoC 컨테이너 7부 02 Apr 2021
-
IoC 컨테이너 6부 29 Mar 2021
-
IoC 컨테이너 5부 27 Mar 2021
-
IoC 컨테이너 4부 23 Mar 2021
-
IoC 컨테이너 3부 20 Mar 2021
-
IoC 컨테이너 2부 18 Mar 2021
-
IoC 컨테이너 1부 12 Mar 2021
-
스프링 PSA 07 Jan 2021
-
스프링 @AOP 실습 07 Jan 2021
-
프록시 패턴 06 Jan 2021
-
스프링 AOP 04 Jan 2021
-
의존성 주입(Dependency Injection) 04 Jan 2021
-
스프링 빈(Bean) 02 Jan 2021
-
스프링 IoC 컨테이너 01 Jan 2021
-
스프링 IoC 01 Jan 2021