HTTP 특성과 쿠키, 스토리지 그리고 JWT
배경
Spring Security 학습을 앞두고, 로그인(인증)과 관련하여 여러가지 개념이 혼동되었다. 많은 개념들이 존재하는데 이 참에 간단하게라도 한 번 짚고 넘어가면 좋을 것 같다는 생각이 들어 간단하게 정리해본다.
HTTP의 주요 특징
- ’비연결성과 무상태성’
- 서버가 다수의 클라이언트와 계속 연결을 맺고 있다면 자원낭비가 과다하다.
- 따라서 HTTP 프로토콜은 요청에 대한 응답을 주고나면 연결을 끊어버린다.
- 위와 같은 전제라면, 웹사이트를 한 번 로그인하면 페이지를 이동할때마다 서버는 클라이언트를 식별할 수 없다.
- 어떻게 이 문제를 해결할 수 있을까?
1. 쿠키 기반 인증
- 클라이언트가 특정 웹서버(사이트)를 방문할 경우, 서버를 통해 클라이언트의 브라우저의 작은 공간에 설치되는 작은 기록 정보파일
- 쿠키 값은 key-value 형태로 저장
- 서버 : 응답 헤더 중 ‘SET-Cookie’에 담음
- 클라이언트 : 요청 헤더 중 ‘Cookie’에 Value값을 담아서 보내게 된다.
쿠키 기반 인증의 장단점
- 쿠키는 보안에 취약하다
- 요청 시 쿠키의 Value(값)이 그대로 노출되며 이에 따라 유출 및 조작 가능성이 다분하다.
- 또한 용량제한으로 인해 많은 정보를 담을 수 없으며, 네트워크 부하가 심해지게 될 수 있고 브라우저간 공유가 불가능하다.
2. Cookie & Session 기반
- 쿠키 기반 인증의 가장 큰 문제인 ‘보안’문제를 해결하고자 함
- 클라이언트의 인증정보(Value)를 서버(대부분은 톰캣과 같은 WAS 내)에 저장(세션 저장소)
- 서버는 클라이언트의 인증 요청에 대하여 인증정보는 서버 내에 세션 저장소에 저장 후, 클라이언트 식별자인 JSESSIONID를 쿠키에 담아서 보낸다. 형식은 아래와 같음
- 클라이언트는 서버에 요청을 보낼때마다 JSESSIONID 값을 쿠키에 담아서 보내고 서버는 해당 값의 유효성을 판단해서 클라이언트를 식별한다.
HTTP/1.1 200
Set-Cookie: JSESSIONID=FDB5E30BF20045E8A9AAFC788383680C
Cookie & Session 기반 장단점
- JSESSIONID값이 외부에 노출되어도 단순한 클라이언트 식별값이기 때문에 개인정보를 담지 않으므로 쿠키에 비해서 부담이 덜하다.
- 그러나, 해커가 중간에 탈취 후 클라이언트로 위장할 수도 있다.
- 또한 어쨋든 서버 내에 존재하는 ‘세션 저장소’ 내에 식별값을 저장하므로 서버 부하가 생길 수도 있다.
3. JWT 기반 인증
- JWT란 Json Web Token의 약자로 인증에 필요한 정보들을 암호화시킨 토큰을 의미한다.
- 쿠키/세션 방식과 유사하게 HTTP Header에 JWT 토큰을 실어서 서버가 클라이언트를 식별한다.
JWT 구조
aaaaaa.bbbbbbb.cccc
- 간단한 예시지만, JWT는 .을 구분자로 3개의 문자열의 조합으로 구성된다.
- JWT를 디코딩하면 JWT는 3가지로 구성된다.
- Header
{ “alg” : “HS256”,
“typ: “JWT”
}
- alg과 typ는 각각 암호화할 해싱알고리즘 및 토큰 타입을 의미한다.
- Payload
{
“sub”: “1234567890”,
“name” : “John Doe”,
“iat” : 1516239022
}
- 토큰에 담을 정보를 담고있다.
- 토큰의 유효기간, 고유한 클라이언트를 식별할 ID값을 담고있다.
- JSON이름에서 유추가능하듯이 Key-Value형태로 이뤄져있으며 이를 ‘Claim’이라고 한다.
- Signature

- 인코딩된 Header, Payload를 더한 뒤 비밀키로 해싱하여 생성한다.
- Signature는 서버 측에서 관리하는 비밀키로 생성하기에, 비밀키가 유출되지 않는 이상 복호화할 수 없다.
- 따라서 Signature는 토큰의 위변조를 판별하는데 사용한다.
- 클라이언트의 인증 요청에 서버는 검증 후 고유 ID등의 정보를 Payload에 담고 비밀키를 사용해 Access Token(JWT)를 발급한다.
- 클라이언트는 전달받은 토큰을 저장 후 서버 요청시마다 토큰을 요청 Header 중 Authorization에 포함시켜 전달한다.
- 서버는 토큰의 Signature를 비밀키로 복호화 후 위변조 여부 및 유효기간을 판별한 후 요청을 응답해준다.
장점
- 세션과 달리 인증 정보에 대하여 별도의 저장소 필요가 없다.
- 서버의 저장에 대한 부담이 없고 Header와 Payload를 토대로 Signature를 생성하기에 데이터 위변조를 막을 수 있다.
- 확장성이 우수하다.
- 토큰 기반으로 다른 로그인 시스템(인증)에 접근 및 권한 공유가 가능
- Oauth의 경우, 소셜 로그인을 통해 다른 웹서비스에서도 로그인이 가능하다.
단점
- Header, Payload, Signature 등의 많은 정보를 포함하므로 네트워크 통신 시 크기가 상대적으로 크기에 인증요청이 많을 시 네트워크 부하가 심해질 수 있다.
- Payload 자체는 암호화되지 않는다. 따라서 중요한 유저 정보는 담을 수 없다.
- 토큰 탈취 시 대처가 힘들다.
- 토큰은 유효기간 만료시까지 사용된다.
- 특정 사용자가 접속에 이용한 토큰을 강제로 만료할 수도 없다. 그러나, 쿠키/세션기반 인증은 세션 저장소 내에서 해당 클라이언트 식별자를 삭제 가능하다.
JWT의 보안 전략
- 토큰의 만료시간을 짧게 설정한다.
- 그러나 이 경우에 사용자가 짧아진 주기만큼 자주 로그인을 해야하기에 사용자 이용성에 불편함을 초래한다.
- Sliding Session
- 글을 작성 중에 토큰 만료시, 작성 중 글이 삭제되는 일 등을 서비스를 이용 중인 클라이언트에게 자동으로 토큰 만료 기한을 늘려주는 방법이다.
- 글 작성, 결제 등에 있어서 새로운 토큰을 발급해줄 수 있다.
- Refresh Token
- 클라이언트의 로그인 요청 시, 서버에서 Access Token, Refresh Token을 각기 발급한다.
- Refresh Token은 Access Token이 만료되었을때, Refresh Token을 사용하여 Access Token의 재발급을 요청한다.
- 서버는 DB 내에 저장된 Refresh Token과 클라이언트의 요청의 Refresh Token값을 비교하여 유효한 경우 새로운 Access Token값을 발급해주고, 만료되었을 경우에 사용자에게 로그인을 요청한다.
- 이 방법을 이용하면 Access Token의 만료기한을 짧게 설정 가능하며 사용자가 자주 로그인을 할 필요성이 없어진다. 또한, 서버 내에서 Refresh Token을 관리하므로 서버 내에서 만료시킬 수 있다.
- 그러나, 서버 내 Refresh Token을 별도의 Storage에 저장되어야 하므로 추가적 I/O작업이 발생한다. 이에 따라 가볍게, 빠르게 인증할 수 있는 JWT의 주요 장점이 퇴색된다는 단점이 있으며, 클라이언트 역시 탈취 방지를 위해서 Refresh Token을 보안이 유지되는 공간에 저장해야한다.
- Q) 클라이언트가 Refresh Token을 저장하는 곳은 어디며 이는 또 탈취 방지와 어떤 연관이 있는가?
참고 : 테코블
남은 의문
- 클라이언트의 토큰 값을 어디에 저장하는지?
- 클라이언트가 Refresh Token을 저장하는 곳은 어디며 이는 또 탈취 방지와 어떤 연관이 있는지?