안녕하세요 서버는 클라이언트를 인증하는 방식으로 3가지 방식을 사용할 수 있습니다.
오늘 소개할 3가지는 쿠키
,세션
그리고 토큰
입니다.
이번 포스팅에서는 각 인증 방식의 특징과 장단점을 알아보겠습니다 🔥
현대인들에게 없어서는 안될 web
은 HTTP 프로토콜
이라는 규약을 통해 작동합니다.
클라이언트는 서버에게 Request 를 보내고, 서버는 해당 Request 를 처리 후 적절한 Response 를 생성하여 보냅니다.
이때 Http 통신
은 Connectionles
와 Stateless
특성을 가지고 작동합니다 🏋️
Http 통신
을 하기 위해서는 클라이언트와 서버가 연결이 되어있어야 합니다.
이 커넥션을 유지하는 것 자체도 부담이 되며, 수 없이 많은 클라이언트가 동시에 서버에 요청을 하는 경우 그 만큼 많은 커넥션을 생성합니다.
이는 서버 입장에서 큰 부담이 되며 부하가 될 수 있는데 이를 해결하기 위해 Http 프로토콜
위에서 동작하는 Http 통신
은 통신을 한번 할 때 클라이언트와 서버를 연결하고, 통신이 끝나면 바로 연결을 끊습니다 ✂️
이를 통해 서버 자원을 효율적으로 관리하고 가능한 여러 클라이언트의 요청에 응답합니다.
이렇게 한 클라이언트가 여러번의 요청을 보내도 커넥션이 계속 끊어졌다, 연결됐다를 반복하는 특성을 Connectionless
라고 합니다.
장점
[1] 서버의 자원을 좀 더 효율적으로 사용 가능하며 더 많은 요청을 처리할 수 있습니다.
단점
[2] 한번 맺어진 커넥션은 유지되지 않기 때문에 요청마다 매번 커넥션을 만들어주어야 합니다.
Stateless 특성은 Http 통신
이 이전 요청의 상태를 기록하지 않기 때문에 서버가 클라이언트를 식별할 수 없는 특성을 말합니다.
Connectionless 특성 때문에 생겨나며, 한번의 요청 후 커넥션이 유지 되지 않기 때문에 다음 요청시 서버는 클라이언트를 식별하지 못합니다.
즉, 이번 요청이 어떻게 끝났느냐에 따라 다음 요청이 영향을 받지 않고 모든 요청이 독립적입니다.
만약 다음 요청이 이전 요청과 관련된 요청이면 서버는 이전 요청을 기억하지 못하기에 한번의 요청에 이전 요청 내용까지 모두 전달해야합니다.
Stateless 에 반대되는 특성은 Stateful 이며 이는 이전 상태를 보존하며 이전 요청의 내용을 기억하며 다음 요청에 반영할 수 있습니다.
웹의 개인화
는 웹의 발전으로 인해 생겨났으며 클라이언트에 맞게 개인화된 웹 사이트를 제공하는 웹의 특성을 말합니다.
예를 들어 특정 클라이언트가 신규 회원인 경우, 환영 메세지를 보낸다거나, 특정 브랜드를 많이 검색한 클라이언트에게 해당 브랜드의 신발을 추천 정보로 보여주는 등 서버는 클라이언트의 상황에 맞는 응답을 서버는 제공해야하는 필요성이 생겨났습니다.
웹의 개인화
는 결국 특정 클라이언트에 맞는 데이터(정보) 를 서버에서 제공해야하기에 클라이언트를 식별를 요구합니다.
하지만 기존 Http 통신
은 Connectionless, Stateless 특성을 가지기에 클라이언를 식별할 수 없습니다.
이러한 한계를 극복 및 웹의 보안을 위해 생겨난 것이 쿠키(Cookie)
방식입니다 🔥
첫번째로 알아볼 인증 방식은 쿠키(Cookie)입니다 🍪
쿠키는 Key-Value
형식의 문자열 덩어리 입니다.
클라이언트가 어떠한 웹 사이트를 방문할 경우, 그 사이트가 사용하고 있는 서버를 통해 클라이언트의 브라우저에 설치되는 작은 기록 정보 파일
입니다.
쿠키의 가장 두드러지는 특징은 사용자 관련 정보를 브라우저가 관리한다는 것입니다 👨🔧
1. 클라이언트의 첫 Http Request
2. 서버의 Http Response
Set-Cookie
항목에 쿠키를 담아서 전달합니다. 클라이언트는 Set-Cookie
헤더에 있는 쿠키를 브라우저에 저장합니다.3. 클라이언트의 Http Request + Cookie
Domain
속성과 Path
속성을 사용)4. 서버의 클라이언트 식별
2가지 종류의 쿠키가 있으며, 둘의 차이점은 쿠키의 파기 시점
입니다.
1. 세션 쿠키
만료일을 설정하지 않았기 때문에 브라우저를 종료하면 파기됩니다.
사용자가 특정 사이트를 탐색할 때 선호 사항, 임시 설정 등을 저장하는 쿠키
ex) 최근 본 상품, 최근 검색어
2. 지속 쿠키
디스크에 저장되어서 만료일까지는 브라우저를 끄거나 재부팅하여도 남아있습니다.
다음 방문에도 유지돠는 설정 정보나 로그인 정보등을 저장하는 쿠키
ex) 일주일간 팝업 보지 않기, 로그인 유지
쿠키의 방식에 대해서 알아보았습니다.
하지만 쿠키는 다양한 한계점이 존재합니다.
이러한 단점을 보완해주는 것이 세션
입니다.
여기서 세션방식은 보통 쿠키와 함께 작용됩니다.
세션의 인증 방식부터 알아보겠습니다 🏋️
1. 클라이언트의 첫 Http Request
2. 서버의 Http Response
3. 클라이언트의 Http Request
4. 서버의 클라이언트 식별
앞에서 세션의 인증 방식에서 살펴본 바와 같이 세션은 클라이언트의 인증 정보와 관련된 민감한 정보를 서버에서 관리합니다.
서버는 클라이언트의 로컬 컴퓨터보다 강한 보안 기술이 구현되어 있기에 악의적인 보안 공격에 안전합니다.
세션은 쿠키의 취약한 보안성을 보완하기 위해 만들어진 기술이지만
역시나 한계가 존재합니다.
Load Balancer
등의 해결방법이 있습니다. 하지만 이러한 해결방법은 복잡한 로직을 요구합니다.이처럼 세션에도 한계점이 존재하기에 토큰(Token)
을 이용한 인증 방식이 탄생합니다.
여기서 토큰
이란 인증에 필요한 정보를 암호화시킨 것입니다.
이번 포스팅에서는 가장 대중화된 토큰인 JWT
를 알아보겠습니다 🔥
본격적으로 토큰
기반 인증 시스템을 알아보기 전에 인증(Authentication)
과 인가(Authorization)
을 알아보겠습니다.
인증(Authentication) 은 사용자의 신원을 검증하는 프로세스를 뜻합니다.
앞에서도 알아보았듯이 웹은 Http 프로토콜 기반으로 동작합니다.
따라서 Connectionless, Stateless 한 특성을 가지는데 이러한 특성은 모든 요청마다 인증
을 요구합니다.
매번 로그인을 한다는 것은 클라이언트에게 매우 번거로운 작업이 될 수 있습니다.
이러한 작업을 막기위해 Cookie
, Session
그리고 Token
을 사용하는 것입니다.
인가(Athorization) 은 사용자가 어떠한 자원에 접근할 수 있는지를 확인하는 절차입니다.
인가는 인증 이후의 프로세스입니다.
가령 특정 웹 사이트의 관리자 기능은 아무 클라이언트에게 접근하는 것을 허용하면 안됩니다.
즉 관리자에게만 해당 기능을 제공해야하는데 이러한 것을 인가
라고 합니다.
해당 이미지는 토큰을 이용한 인증 방식을 도식화한 이미지입니다 😛
1. 클라이언트의 첫 Http Request
2. 서버의 Http Response
비대칭키
가 사용됩니다.3. 클라이언트의 Http Request
4. 서버의 클라이언트 인증
JWT 토큰
이란 인증에 필요한 정보들을 암호화시킨 JSON 토큰을 의미합니다.
즉 토큰 구현 방법중 하나입니다.
JWT 는 JSON 데이터를 Base 64 URL-safe Encode
를 통해 인코딩하여 직렬화한 것이며, 토큰 내부에는 위변조 방지를 위해 개인키를 통한 전자서명이 들어있습니다.
해당 이미지에서 알 수 있듯이 JWT
는 3가지 파트로 나뉩니다.
Header
JWT Header 에는 토큰의 타입
과 토큰의 해시 알고리즘 유형
정보가 들어갑니다.
Payload
JWT Payload 에는 토큰에서 실질적으로 사용될 정보인 클레임(Claim)
이 들어 있습니다.
클레임은 다시 3가지 종류로 나뉩니다.
- Register Claim : 등록된 클레임은 토큰 정보를 표현하기 위해 이미 정해진 종류의 데이터들입니다. 모두 선택적으로 작성이 가능합니다.
Key 값은 간결함을 위해 모두 길이 3의 String입니다.
iss : 토큰 발행자(Issuer)
sub : 토큰 제목(Subject) 일반적으로 사용자의 이메일을 사용
exp : 토큰 만료 시간(Expiration)
lat : 토큰 발급 시간(Issued At)
jti : JWT 식별자(JWT ID) (중복 방지를 위해 사용)
aud : 토큰 대상자(Audience)
nbf : 토큰 활설 날짜(Not Before)
- Public Claim : 공개 클레임은 사용자 정의 클레임으로 공개용 정보를 위해 사용됩니다. 충돌 방지를 위해 URI 포맷을 이용합니다.
{ "https://naver.com" : true }
- Private Claim : 비공개 클레임은 사용자 정의 클레임으로 서버와 클라이언트 사이에 임의로 지정한 정보를 저장합니다.
{ "token_type" : access }
Signature
서명이라고 불리며 앞에서 살펴본 Header
와 Payload
값을 Base 64 URL-safe Encode
를 통해 인코딩하고, 인코딩한 값과 서버가 가지는 유일한 Secret Key
를 합쳐 Header
에서 정의한 해시 알고리즘으로 암호화를 합니다.
해당 이미지는 JWT 에 구성요소를 한눈에 이해하기 위한 이미지입니다 🔥
Header
와 Payload
는 단순히 인코딩된 값이기 때문에 외부에서 복호화 및 조작이 가능하지만
Sigature
는 서버측에서 관리하는 Secret Key
가 유출되지 않는 이상 복호화할 수 없습니다 🚫
이렇게 생성된 JWT 는 클라이언트의 스토리지 혹은 쿠키 등의 저장이 됩니다.
이후 Request Authorization
헤더에 JWT 를 담아 요청을 보냅니다.
그렇다면 서버는 어떻게 서버의 오버헤드 없이 JWT 만을 복호화해서 인증과정을 수행할까요? 🤔
이 질문에 대한 답을 찾기 전 기억해야할 점은 JWT의 Header 와 Payload 는 단순히 인코딩되어 있기 때문에 충분히 위변조가 가능하다는 점입니다 ❗️
사실 JWT 의 본래 목적은 정보 보호
가 아닌 위조 방지
입니다 ❗️
예를 들어 JWT Payload의 특정 부분이 수정되었다고 가정해봅시다.
이렇게 수정된 JWT 를 Request로 받은 서버는 JWT의 Header 와 Payload 를 이용해서 Signature를 다시 생성해봅니다.
만약 앞에서 가정한것처럼 Payload의 특정 부분이 수정되었다면 Signature 값이 JWT 의 Signature와 다르겠죠?
이렇게 대조 결과가 일치하지 않는 경우 유저의 정보가 임의로 조작되었다는 뜻이므로 해당 자원에 대한 인증/인가가 불가능합니다 🚫
장점
1) Header와 Payload 를 가지고 Signature 를 생성하므로 데이터 위변조를 방지할 수 있습니다.
2) 세션과 달리 서버의 별도의 저장소가 필요없습니다.
3) JWT 는 토큰에 대한 기본 정보와 전달할 정보 및 토큰이 검증됬음을 증명하는 서명 등 필요한 모든 정보를 자체적으로 가지고 있습니다.
4) 세션과 달리 무상태(Stateless)가 되어 서버의 확장성이 우수합니다.
5) Oauth 등과 함께 이용하기에 적절합니다.
6) 모바일 환경에서는 쿠키, 세션같은 인증 방식이 존재하지 않으며 오로지 토큰을 이용해서 인증을 합니다.
7) JWT 자체가 인증된 상태라는 것을 증명하는 것임으로 세션처럼 따로 DB 를 조회하는 오버헤드가 없습니다.
단점
1) 토큰 자체에 정보를 담고 있으므로 보안적인 측면에서 오히려 양날의 검이 될 수 있습니다.
2) Payload에 3종류의 Claim(Register,Public,Private) 를 저장하기 때문에 정보가 많을수록 토큰의 길이가 늘어나고 네트워크에 부하가 될 수 있습니다.
3) Payload 는 암호화된것이 아니라 인코딩되었기 때문에 중요한 정보가 실수로 포함되면 데이터 유출이 발생할 수 있습니다.
4) 토큰은 클라이언트쪽에서 저장되기 때문에 혹여나 토큰 자체가 탈취되면 대처하기가 어렵습니다.
앞에서도 살펴 보았듯이 JWT에도 허점이 존재합니다. 예를 들어 JWT가 탈취당하면 대처하기가 매우 어렵습니다. 이를 해결하기 위해 현업에서는 Access Token
과 Refresh Token
을 사용하는 이중 인증 방식을 사용합니다 👨💻
간단하게 설명하면 Access Token
의 만료기간을 짧게 설정하는 것입니다.
그러면 클라이언트는 짧은 시간의 주기마다 다시 인증과정을 거쳐야하는 번거로움이 있습니다. 이때 Refresh Token
을 사용하여 새로운 Access Token
을 발급받습니다 ❗️
Access Token : 클라이언트가 갖고있는 실제로 유저의 정보가 담긴 토큰으로, 클라이언트에서 요청이 오면 서버에서 해당 토큰이 있는 정보를 활용하여 응답 생성(앞에서 살펴본 JWT)
Refresh Token : 새로운 Access Token을 발급해주기 위한 토큰입니다. 즉 Access Token의 재발급에 관여하는 토큰입니다.
Access Token
과 Refresh Token
의 원리에 대해 살펴보겠습니다 👨💻
[1] 클라이언트는 로그인을 하고 로그인에 성공했을 경우 서버는 클라이언트에게 Access Token
과 Refresh Token
을 발급합니다.
[2] 서버는 서버 스토리지에 Refresh Token
을 저장하고 클라이언트는 Access Token
과 Refresh Token
을 쿠키, 세션 혹은 스토리지에 저장하고 Request가 있을 때마다 두개의 토큰을 헤더에 담아서 보냅니다.
[3] 클라이언트는 추후 Request 마다 Refresh Token
과 Access Token
을 같이 보냅니다.
서버는 위변조 검사와 함께 받은 Access Token
의 만료기간을 확인합니다.
[4] 만약 Access Token
의 만료 기간이 끝났을 경우, 서버는 자신의 스토리지에 있는 Refresh Token
과 비교해서 클라이언트가 보낸 Refresh Token
과 비교해서 일치하면 새로운 Access Token
을 발급해줍니다.
[5] 클라이언트가 로그아웃 하는 경우 서버는 Refresh Token
을 삭제합니다. 또한 Refresh Token
의 만료기간이 지난 경우 클라이언트는 비로소 다시 인증 과정을 거쳐야합니다.
보통 Refresh Token
의 만료기간은 Access Token
의 만료기간보다 긴 2주로 설정합니다 👮♀️
HTTP의 특성과 쿠키, 세션, 토큰
Access Token + Refresh Token Authentication
[web] JWT 토큰 인증 이란?
Access Token & Refresh Token 원리