cookie와 session를 통한 인증
구글이나 다른 브라우저를 사용하다 보면 '쿠키(cookie)를 저장하겠습니까?' 라는 문장을 자주 볼 수 있습니다. 여기서 쿠키란 클라이언트가 웹사이트에 접속할 때 필요한 정보를 서버에서 발급하여 저장하는 것을 말합니다.
쿠키의 등장 배경에는 로그인 유지가 있습니다. 웹사이트를 이용할 때 쿠키가 없다면 ID/PW를 이용해 서버에 지속적인 요청을 날려야 하는데, 이러한 과정을 단축하기 위해 정보를 담아서 쿠키를 발급한다면 매번 요청하는 번거로움을 방지할 수 있습니다.
하지만 쿠키에는 단점이 존재합니다. 외부 요인에 의해 데이터를 탈취당했을 때 ID/PW와 같은 민감한 정보도 함께 노출되기 쉽습니다. 또한, 조작된 데이터에 대한 대처 방안이 없으므로 보안에 관련하여 취약한 부분이 많습니다.
세션은 새로운 기술이 아닌 쿠키의 단점을 보안하여 나온 기술입니다. 민감정보를 매번 ID/PW를 서버에 전달하여 인증을 경우, 탈취당하기 쉽다는 단점을 세션 스토리지(session storage)를 활용하여 보완했습니다.
기존의 쿠키는 http의 특징 중 하나인 무상태성(stateless)을 기반으로 하여 클라이언트단에서 정보를 관리했습니다. 클라이언트는 비교적 보안이 약하므로 탈취의 위험성을 가지고 있지만, 세션 스토리지는 서버 저장소에 정보를 보관하고, 쿠키에 담아 클라이언트가 요청할 때 마다 인증하는 방식이므로 쿠키보다 보안성이 좋은 기술입니다. 하지만 세션 또한 단점이 존재합니다.
우선 http의 장점인 무상태성을 위반합니다. 서버에 세션 저장소를 사용하므로 stateful한 특징을 가지고 있습니다. stateful할 경우, 서버 확장을 위해 scale-out을 하면 기존 서버에 있는 로그인 정보를 다른 서버에도 저장해야 하므로 중앙 세션 저장소를 필요로 합니다. 당연히 서버 비용 문제가 발생하게 됩니다.
유저가 증가하게 되면 메모리를 많이 차지하는 점도 단점입니다. 세션은 매번 서버에 호출하게 되는데 서버에 부하가 걸릴 수도 있고, 클라이언트와 서버 사이의 통신이기 때문에 쿠키에 비해 속도도 느린 단점이 존재합니다.
쿠키와 세션 두 가지의 단점을 보완하기 위해 등장한 기술이 JWT 입니다.
한 눈에 보는 쿠키와 세션의 차이
너무 깔끔하게 정리하셔서 링크 들어가서 읽어보시면 좋을 것 같습니다.
session vs token
http의 stateless 특성으로 인해 통신의 상태가 저장되지 않는다는 점을 앞에서 알 수 있었습니다. 이 문제를 해결하기 위해 session과 token이 탄생했습니다.
로그인을 시도할 때 인증(Authentication)을 위해 session / token을 발급해주고, 새로운 request를 보낼 때 마다 발급된 session / token을 보내 인가(Authorization)를 처리합니다.
두 가지 방법의 가장 큰 차이점은 session과 token의 저장 위치 입니다.
session은 DB서버에 저장되고, token은 클라이언트에 저장됩니다.
위에서 설명한 것과 같이 session이 아닌 token을 사용하는 이유는 저장위치에 있다고 생각합니다. 서비스가 커지고 대용량 트래픽을 대비하기 위해서는 확장성을 생각해야 합니다.
session의 경우, 사용자가 많아지면 서버에 과부하가 발생하고 부하 분산을 위해 scale-out을 해야 하는데 매 요청마다 서버가 달라질 수 있습니다. 해결하기 위한 다른 방법도 존재하지만 서버 비용이 발생하기 때문에 token이 더 각광받는 것 같습니다.
token의 경우, 클라이언트에 access token을 발급하여 signature 대조를 통한 인증/인가 방식을 사용합니다. 서버 저장소를 사용하지 않아서 비용 부담을 줄일 수 있으며, 발급 주기에 차이를 두고 서버에 refresh token을 발급하여 access token 재발급을 통해 탈취에 대한 위험성도 줄였습니다.
헤더에서는 typ으로 token의 타입과 alg를 통해 어떤 알고리즘을 적용했는지 알 수 있다.
페이로드에서는 7가지 Claim으로 사용자의 정보를 저장할 수 있습니다. 어떤 Claim을 사용할 지는 정보의 용도에 따라 다르기 때문에 각 특징에 대해 알아봅시다.
iss (Issure) : 토큰 발급자
nbf (Not Before) : 토큰 활성 날짜
sub (Subject) : 토큰 제목
exp (Expiration Time) : 토큰 만료 시간(현재 시간 이후)
iat (Issured At)" : 토큰 발급 시간
adu (Audience)" : 토큰 대상자
jti (JWT id)" : 토큰 식별자(iss가 여러 명일 때 구분하기 위해)
Claim은 총 3가지로 구성 되어 있으며 등록, 공개, 비공개가 있습니다.
헤더와 페이로드는 암호화 없이 사용할 수 있는 base64 인코딩을 사용하므로 탈취될 경우 문제가 발생합니다. 그래서 중요한 개인 정보를 제외한 식별 가능한 정보만을 포함해야 합니다.
시그니쳐에서는 앞의 헤더와 페이로드의 값을 인코드하여 합친 후 this-is-secret-key라는 개인 키를 통해 암호화하는 역할을 합니다. 개인 키는 서버만 가지고 있으므로 다른 클라이언트가 토큰을 탈취하더라도, 개인 키가 없어서 복호화 할 수 없습니다.
JWT의 장점을 한 문장으로 표현하자면
stateful 해야 하는 session의 단점을 보완하기 위해 만들어진 JWT는 별도의 session 저장소를 강제하지 않기 때문에 stateless하여 확장성이 뛰어나고, signature를 통한 보안성까지 갖추고 있다.
-> jinyoungchoi95 님의 문장을 인용했다.
[출처]