사용자의 신원을 확인하고, 사용자가 자격을 가지고 있는지 확인하는 과정은 다양한 방식이 있습니다. 그중에서 REST API 통신을 사용하는 백엔드 서버에 가장 활용도가 높은 토큰 인증 방식을 소개합니다.
- 세션 기반 인증(Session-Based Authentication):
사용자 인증 후 서버에서 세션을 유지합니다.
세션 식별자를 쿠키 또는 URL 매개변수로 전달하여 사용자를 식별합니다.
서버는 세션 저장소에서 세션 정보를 관리하고 인증된 사용자를 추적합니다.
주로 웹 애플리케이션에서 많이 사용되며, 서버 사이드에서 상태를 유지하는 방식입니다.- 기본 인증(Basic Authentication):
사용자 이름과 비밀번호를 인코딩하여 인증 요청에 함께 전송합니다.
클라이언트가 요청을 보낼 때마다 인증 정보가 함께 전송되어 서버에서 인증을 수행합니다.
주로 API 및 서비스 엔드포인트에서 사용되며, HTTPS와 함께 사용되어야 보안성이 유지됩니다.- OAuth:
제3자 애플리케이션의 인증과 권한 부여를 위한 개방형 표준 프로토콜입니다.
사용자는 OAuth를 통해 인증 서버를 통해 인증을 수행하고, 인증 서버는 액세스 토큰을 발급하여 애플리케이션에 제공합니다.
OAuth는 API 호출이나 제한된 리소스에 대한 권한을 관리하기 위해 널리 사용됩니다.- 토큰 인증(Token-Based Authentication):
토큰 기반 인증은 서버가 사용자에게 발급하는 토큰을 사용하여 인증을 수행하는 방식입니다.
사용자가 자격 증명(일반적으로 사용자 이름과 비밀번호)을 제공하면 서버는 유효한 경우에 액세스 토큰을 발급합니다.
액세스 토큰은 클라이언트가 보유하고, 이를 이용하여 인증 및 권한 부여를 수행합니다.
토큰 기반 인증이 생기기 이전에는 세션 기반 인증을 사용했습니다. 세션은 이전 글에 자세히 정리했으므로 자세한 설명은 생략합니다. 참고 : 해싱/쿠키/세션
세션 기반 인증은 사용자가 인증을 완료해 로그인하면 서버에서 해당 사용자의 세션을 유지해야 하므로 메모리의 일부가 소모되는데 이용자가 늘어날수록 가용메모리가 줄어들어 서버의 성능이 저하될 수 있습니다. 이런 서버의 부하를 줄이기 위해 고안된 것이 토큰 기반 인증입니다.
토큰은 공연장 입장팔찌나 회사 출입증카드로 생각하면 이해가 쉽습니다.
클라이언트가 ID와 PW를 담아 로그인 요청을 보내면 서버는 ID, PW가 일치하는지 확인 후 암호화 된 엑세스 토큰과 리프레쉬 토큰을 생성해서 리프레쉬토큰은 서버(DB)에 보관하고, 엑세스 토큰은 클라이언트에 보냅니다.
클라이언트는 토큰을 쿠키, 로컬 스토리지, 세션 스토리지, 메모리(리액트의 State)와 같은 곳에 저장합니다.
이후 HTTP헤더에 토큰을 담아서 요청을 보내면 서버는 토큰을 해독하여 서버가 발급한 토큰인지 확인한 후 맞으면 요청을 처리하여 응답을 보내줍니다.
1.무상태성&확장성
서버는 클라이언트의 인증 정보를 저장할 필요할 필요가 없고, 인증된 사용자 request의 상태를 관리하지 않아도 되므로, 무상태성을 가집니다. 서버가 여러개일 경우에도 각각의 서버가 독립적으로 토큰의 유효성을 검증할 수 있고, 토큰 생성용 서버를 따로 둘 수 도 있어서 시스템 수평 확장에도 유리합니다.
2.안정성
토큰은 서버에서 서명된(sign) 형태로 발급되며, JWT(JSON Web Token) 같은 토큰 형식을 사용하면 토큰의 내용을 암호화하여 안전하게 전송할 수 있습니다.
3.권한부여에 용이함
토큰은 클라이언트의 권한 정보를 포함할 수 있으므로, 인증 외에도 권한 부여를 효과적으로 관리할 수 있습니다. 토큰에는 사용자의 역할(Role)이나 추가적인 권한 정보를 포함하여 접근 제어를 유연하게 구성할 수 있습니다.
4.범용성이 넓음
Base64 URL Safe Encoding 을 이용하기 때문에 URL, Cookie, Header 어디에서든 모두 사용가능합니다.
1.토큰 크기 고려해야함
토큰은 클라이언트와 서버 간의 통신에 사용되므로 토큰의 크기가 클수록 네트워크 부하가 증가하고, 세션에 비해 상대적으로 많은 네트워크 트래픽을 사용합니다. 따라서 효율적인 토큰 크기와 전송 방식을 고려해야 합니다.
2.토큰 관리
출입카드를 분실하면 안되듯이 토큰이 탈취되거나 유출될 경우, 무단 접근이 가능해지며 보안상의 문제가 발생할 수 있습니다. 클라이언트 측에서 토큰 관리에 대한 보안 조치를 취해야 합니다.
서버가 아닌 클라이언트에서 토큰을 관리하므로 보안에 조금 더 취약할 수 있습니다.
또한 토큰에 포함되는 사용자 정보는 토큰의 특성상 암호화가 되지 않기 때문에 공격자에게 토큰이 탈취될 경우, 사용자 정보를 그대로 제공하는 셈이 됩니다. 따라서 민감한 정보는 토큰에 포함하지 말아야 합니다.
3.토큰 유효기간 설정
생성된 토큰은 자동으로 삭제되지 않기 때문에 토큰이 만료되기 전까지는 토큰을 무효화시킬 수 없습니다. 따라서 적절한 만료기한을 지정해야 합니다.
JWT(JSON Web Token)는 웹 표준인 RFC 7519에 정의된 인증 정보를 안전하게 전송하기 위한 토큰 기반 인증 방식입니다. JWT는 JSON 형식을 사용하여 정보를 표현하며, 토큰 자체가 필요한 인증 및 권한 정보를 포함하고 있습니다.
JWT 토큰의 종류
- 액세스 토큰(Access Token) : 권한부여에 사용됨
- 리프레시 토큰(Refresh Token) : 엑세스토큰 재발행에 사용됨
JWT는 Header, Payload, Signature로 구성됩니다.
헤더에서는 어떤 종류의 토큰인지(지금의 경우엔 JWT), 어떤 알고리즘으로 Sign할지 정의합니다.
Base64로 인코딩된 JSON 형식으로 표현됩니다.
{
"alg": "HS256", // "alg"는 사용하는 암호화 알고리즘(HMAC SHA256)
"typ": "JWT" // "typ"은 토큰의 타입(JWT)을 나타냅니다.
}
페이로드에서는 클레임(Claim)이라고 불리는 정보들을 포함합니다. 클레임에는 토큰의 속성과 값을 정의하는 데이터, 사용자의 식별자, 이름, 역할, 권한 등 필요한 정보 등이 담겨있습니다.
페이로드도 Base64로 인코딩된 JSON 형식으로 표현됩니다.
{
"sub": "1234567890",
"name": "John Doe",
"admin": true // 사용자의 권한 여부
}
Signature에서는 원하는 비밀 키(Secret Key)와 Header에서 지정한 알고리즘을 사용하여 Header와 Payload에 대해서 단방향 암호화가 된 데이터로 토큰의 유효성을 검증하는 역할을 합니다.
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret // 서버 측에서만 알고 있는 비밀키
)