세션(Session), 토큰(Token), 쿠키(Cookie), 캐시(Cache)에 대해 비교 정리해보겠습니다.
세션(Session)과 토큰(Token) 정리
위 두 용어는 인증정보가 저장되는 위치에 따라 구분되는 용어이다.
다시 말해, 인증 상태를 어디에 저장하느냐를 기준으로 '세션' 또는 '토큰' 기반의 인증 방식으로 나뉜다.
1. 세션(Session)
인증 정보를 서버에 저장하는 방식이다. 로그인 등의 경우 서버는 세션이 없으면 자동으로 세션을 새로 생성하는데, 이와 함께 고유한 키 역할을 하는 Session ID도 생성한다. 그리고 Set-Cookie 헤더를 통해 JSESSIONID를 클라이언트에게 응답하게 된다.
Set-Cookie: JSESSIONID=Session ID값
※ Set-Cookie : 브라우저에게 "이 값을 쿠키에 저장해"라고 명령하는 HTTP 응답 헤더.
그 이후 클라이언트(브라우저)는 서버로부터 받은 Session ID를 쿠키에 저장하여 매 요청마다 전송하게 되고, 서버는 이 Session ID를 기반으로 서버 내 세션 저장소에서 인증 정보를 조회하는 구조인 것이다. 세션 저장소로는 설정에 따라 JVM 메모리나 별도의 DB 또는 Redis 등이 올 수 있다.
즉, 클라이언트는 단지 Session ID만 가지면서, 실질적인 사용자 정보/인증 상태는 서버 자원이 기억하므로 Stateful 구조라고 표현한다. 인증 상태는 서버 자원에 의존하기에 확장성이나 부하 분산에 불리할 수 있는 특징이 있다.
2. 토큰(Token)
인증 정보를 담고 있는 토큰이라는 것을 클라이언트가 저장/유지하는 방식이다. 대표적으로 'JWT 토큰(JSON Web Token)'이 있다. 클라이언트(브라우저)는 식별 수단 그 자체인 토큰을 서버로부터 받은 후, 매 요청마다 Authorization 헤더 혹은 쿠키(Cookie)에 토큰을 함께 전송한다. 그리고 서버는 이 토큰 내에 담긴 사용자 정보, 만료 시간 등을 확인하는 식으로 매번 검증을 진행하는 구조인 것이다.
토큰은 서버가 클라이언트에게 부여하는 "자격증" 같은 것이고, 클라이언트는 서버 자원에 접근하기 위해 서버에게 이 자격증을 보여주는 것이라고 생각하면 쉽다. 서버는 토큰을 검증만 하고 별도로 인증 상태를 저장하지 않기에 Stateless 구조라고 표현한다. 토큰은 서버 자원을 적게 쓰기 때문에 수평 확장이 쉬운 반면, 토큰 탈취 시 토큰 유효시간 만료 이전까지는 서버가 강제로 무효화시키는데 어려움이 있다.
아래는 로그인 후 토큰을 생성하고 헤더에 정보를 담는 코드 예시이다. 뭔가 복잡해 보이지만 대강의 흐름을 파악해 보자.
@Component
public class TokenProvider {
...
...
public void createTokenAndAddHeader(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) {
// 로그인 성공 후 토큰 처리
String email = authResult.getName();
String authorities = authResult.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.joining(","));
// userid 가져오기
UserResponseDto userResponseDto = userService.findByEmail(email);
String userId = userResponseDto.getUserId();
// Access 토큰(JWT) 생성
String accessToken = createAccessToken(authorities, userId);
// Refresh 토큰(JWT) 생성 후 사용자 도메인에 저장하여 토큰 재생성 요청시 활용한다.
String refreshToken = createRefreshToken();
userService.updateRefreshToken(userId, refreshToken);
// 응답 Header에 토큰 세팅
response.addHeader(TOKEN_ACCESS_KEY, accessToken);
response.addHeader(TOKEN_REFRESH_KEY, refreshToken);
response.addHeader(TOKEN_USER_ID, userId);
}
...
}
쿠키(Cookie)란?
보통 세션&토큰과 함께 나오는 용어라 헷갈리기 쉽지만, 쿠키란 정확히는 문자열(String) 기반 key-value 형태의 데이터이다. 그리고 브라우저는 각 도메인(Domain) 별로 쿠키를 구분하여 저장하는 쿠키 저장소(cookie storage)를 내부적으로 관리하고 있다.
누군가 "쿠키에 저장한다"라고 표현한다면 이때 쿠키 저장소를 말하는 거구나라고 알아들으면 되겠다.
이 쿠키는 주로 인증 정보를 저장하고 전달하는 수단으로 많이 사용될 뿐, 사실 Session ID든, JWT Token이든, 사용자가 원하는 문자열 무엇이든 담을 수 있는 것이다. 다시 말해, 쿠키(Cookie)는 인증 방식이 아니라 인증 정보를 저장하고 전달하는 데 사용되는 데이터 전송 또는 저장 도구이다.
개발자모드(F12) > Application > Cookies 항목에서 확인 가능
쿠키 저장소에 쿠키가 저장되어 있다면, 매 서버 요청마다 브라우저는 해당 쿠키를 자동으로 서버에 함께 전송한다는 특징이 있다(서버 요청 시 브라우저는 쿠키 저장소에 있는 데이터를 꺼내서 Cookie Header에 넣고 서버로 전송).
개발자모드(F12) > Network 탭에서 HTTP 요청에 포함된 쿠키 확인 가능
캐시(Cache)란?
자주 사용할 데이터를 빠르게 제공하기 위해 임시로 저장해두는 공간으로써, 인증과는 별개의 개념이다. 인증이 아닌 "성능 최적화 도구"인 것이다. 캐시는 브라우저, 서버, CDN, 프록시 등 다양한 위치에 존재할 수 있다. 예를 들어, 사용자가 이미지 파일을 요청할 때, 서버가 매번 응답하지 않고 브라우저 캐시나 CDN 캐시를 통해 기존 응답을 제공해 속도를 높일 수 있다.
'Backend' 카테고리의 다른 글
이클립스 프로젝트를 Git에 공유(Commit)하기 (0) | 2019.08.22 |
---|