사용자 A와 사용자 B가 은행 업무를 웹으로 본다고 가정해 보자.
사용자 A는 A가 소유한 계좌에 대해서만 접근이 가능해야 하고 B가 소유한 계좌가 몇 개인지, 잔액이 얼마인지에 대한 정보는 접근해서는 안된다.
따라서 Server 측에서는 A와 B중 누가 요청한지에 대한 정보를 정확히 알아야 한다. 그렇기에 Server는 Client측의 요청 사항에 대한 인증 절차를 거쳐 누구의 요청인지에 대해 확인 하는 절차가 필요하다.
웹서비스를 구현하는데 가장 많이 쓰이는 HTTP 프로토콜은 Connectonless(비연결성)와 Stateless(비상태성) 라는 특징이 있다.
서버는 자원을 절약하기 위해 모든 사용자의 요청에 대해 각각 연결과 해제의 과정을 거치게 되는데 이때 연결 상태가 유지되지 않고 연결이 해제 된 후 상태에 대한 정보가 저장되지 않는 특성이다. 이로 인해 사용자를 식별 할 수가 없어 동일한 사용자의 요청이라 하더라도 매번 요청 할 때 마다 새로운 사용자로 인식 된다는 단점이 있다.
하지만 우리가 사용하고 있는 웹 사이트를 보면 한번 로그인을 한 이후 다시 로그인 할 필요 없이 해당 사이트의 다양한 기능을 사용 할 수 있다.
이러한 HTTP의 특성을 보완하여 서버가 클리언트를 식별 할 수 있게 인증정보를 주고 받는 방법이 필요 하다.
가장 잘 알려진 HTTP 인증 규약이다.
사용자의 이름과 비밀번호를 Base64 인코딩 하여 Header에 담아서 전송하는 방식.
매번 요청마다 사용자의 계정정보를 Header에 담아서 전송하다 보니 보안에 취약하다.
서버의 세션과 사용자의 쿠키를 기반으로 하는 인증 방식
- 인증방식
- Client가 로그인을 위해 해당 정보를 서버에 전달한다.
- Server는 로그인 성공시 사용자를 식별 할 수 있는 고유한 SessionId를 생성하고 이를 Client에 전달한다.
- Client는 전달받은 SessionId를 쿠키에 저장하고 이후 Server에 요청시 쿠키를 실어서 전달한다.
- Server는 쿠키를 받아서 SessionId가 유효한지 확인 한 이후 요청을 처리한다.
# 이중화 구성이나 클러스터링과 같은 시스템 확장이 필요할 시에는 별도 SessionId를 저장하는 서버를 구축해야 함 (ex. Redis)
- 쿠키(Cookie)란?
Client에서 웹 브라우저단에 저장하는 임시 데이터다.
웹 브라우저가 종료될 때 제거되는 Session Cookie와 종료 되더라도 유지되는 Permanent Cookie가 있다.
- 세션(Session)이란?
일정 시간동안 같은 웹 브라우저로 부터 들어오는 일련의 요구를 하나의 상태로 보고 그 상태를 일정하게 유지시키는 기술로 하나의 상태 즉 사용자에 대한 고유한 식별값 (SessionId)를 운영중인 서버에 저장한다.
서버 기반 인증의 문제점
JWT는 토큰 기반 인증 방식으로 Client의 Session 상태를 저장하는게 아니라 필요한 정보를 토큰에 담아서 Client가 가지고 있다가 Server 요청시 담아서 사용한다.
Server는 요청이 오면 Token을 검증하고 해당 요청을 처리합니다.
- 인증방식
- Client가 로그인을 위해 해당 정보를 서버에 전달한다.
- Server는 로그인 성공시 사용자 식별에 대한 정보를 Body에 담아 Token을 발급 이를 Client에 전달한다.
- Client는 전달받은 Token을 Cookie나 local/session storage에 저장하고 이후 Server에 요청시 해당 토큰을 담아서 전달한다.
- Server는 Token을 검증 하고 해당 요청을 처리한다.
- JWT(Json Web Token)이란?
선택적 서명 및 선택적 암호화를 사용하여 데이터를 만들기 위한 인터넷 표준이다.
Json 포맷을 이용하여 사용자에 대한 속성을 저장하는 Claim 기반의 Web Token이다.
JWT의 기본 구성으로는 다음과 같다.
header(aaaaaa) : JWT인 토큰의 유형이나 HMAC SHA256 또는 RSA와 같이 사용되는 해시 알고리즘이 무엇으로 사용했는지 등 정보가 담긴다.
Payload(bbbbbb) : client에 대한 정보나 Meta Data같은 내용이 들어있다.
약속된 claim으로는 iss(발급자), sub(토큰명), aud(대상자), exp(만료일자), nbf(활성일자), iat(발급일자), jti(고유식별자) 등이 선택적으로 포함 될 수 있다. (※모든 일자는 NumericDate 형태)
Signature(cccccc) : header에서 지정한 알고리즘과 secret 키, 서명으로 payload와 header를 담는다.
JWT의 경우 자체 내에 정보를 가지고 있기 때문에 Client가 해독해 정보를 볼 수 있다. 따라서 보안상 민감한 정보는 payload에 담아서는 안된다.
토큰 정보를 수정하기 위해서는 secret키를 알고 있어야 한다.
토큰 기반 인증 방식의 문제점으로는 토큰 기한이 만료될 경우 갑자기 로그인 화면으로 전환되는 문제가 있을 수 있다. 이를 예방하기 위해 토큰 유효 기한을 늘리게 되면 그만큼 보안상 취약해질 가능 성이 있다.
서버 기반 인증 방식과 토큰 기반 인증 방식에는 공통적으로 치명적인 취약점이 존재하는데 sessionId나 token이 탈취될 경우 인증 절차가 바로 뚫리는 상황이 발생하게 된다.
토큰 기반 인증 방식에서는 이를 막기 위해 토큰의 수명이 짧은 access token 과 access token을 다시 발급 받기 위한 수명이 긴 refresh token을 발급하여 관리한다.
Access Token의 경우 수명을 짧게 하여 지속적으로 반복되는 요청에 대해 빠르고 가볍게 처리 할 수 있는 반면 Refresh Token의 경우 Access Token이 만료되면 로그인 대신 Refresh Token을 이용하여 다시 Access Token을 발급 받는다.
단, MSA를 도입할 경우 서버 기반 인증과 마찬가지로 Redis와 같은 별도 Refresh Token을 관리하기 위한 서버가 필요하다