토큰 기반 인증은 기존의 세션 기반 인증이 가지고 있던 한계를 보안하기 위해서 나왔으며, 서버에서 유저의 상태를 관리하던 세션 기반 인증과 다르게 유저의 인증 상태를 클라이언트에 저장 할 수 있어서 서버의 부하나 메모리 부족 문제를 줄일 수 있다.
사용자가 인증 정보를 담아 서버에 로그인 요청을 보낸다.
서버는 데이터베이스에 저장된 사용자의 인증 정보를 확인한다.
인증에 성공하면 사용자의 인증 및 권한 정보를 서버의 비밀 키와 함께 토큰으로 암호화한다.
생성된 토큰을 클라이언트로 전달한다. HTTP 상에서 인증 토큰을 보내기 위해 사용하는 헤더인 Authorization 헤더를 사용하거나, 쿠키로 전달하는 등의 방법을 사용한다.
클라이언트는 전달받은 토큰을 저장한다. 저장하는 위치는 Local Storage, Session Storage, Cookie 등 다양하다.
클라이언트가 서버로 리소스를 요청할 때 토큰을 함께 전달한다. 토큰을 보낼 때에도 Authorization 헤더를 사용하거나 쿠키로 전달할 수 있다.
서버는 전달받은 토큰을 서버의 비밀 키를 통해 검증하며 토큰이 위조되었는지, 토큰의 유효 기간이 지나지 않았는지 등을 확인할 수 있다.
토큰이 유효하다면 클라이언트의 요청에 대한 응답 데이터를 전송한다.
무상태성
서버가 유저의 인증 상태를 관리하지 않으며 서버는 비밀 키를 통해 클라이언트에서 보낸 토큰의 유효성만 검증하면 되기 때문에 무상태적인 아키텍처를 구축할 수 있다.
확장성
다수의 서버가 공통된 세션 데이터를 가질 필요가 없으므로 서버를 확장하기 더 용이하다.
어디서나 토큰 생성 가능
토큰의 생성과 검증이 하나의 서버에서 이루어지지 않아도 되므로 토큰 생성만을 담당하는 서버를 구축할 수 있다. 그러므로 여러 서비스 간의 공통된 인증 서버를 구현할 수 있다.
권한 부여에 용이
토큰은 인증 상태, 접근 권한 등 다양한 정보를 담을 수 있어서 사용자 권한 부여에 용이하다. 어드민 권한 부여 및 정보에 접근할 수 있는 범위도 설정할 수 있다.
JSON 객체에 정보를 담고 이를 토큰으로 암호화하여 전송할 수 있는 기술로 토큰 기반 인증 구현 시 대표적으로 사용하는 기술이다. 클라이언트가 서버에 요청을 보낼 때, 인증정보를 암호화된 JWT 토큰으로 제공하고, 서버는 토큰을 검증하여 인증정보를 확인할 수 있다.
JWT는 Header, Payload, Signature로 .으로 나누어진 세 부분으로 존재한다.
Header
Header는 HTTP의 헤더처럼 토큰을 설명하는 데이터가 담겨 있으며 토큰의 종류, 시그니처를 만들 때 사용할 알고리즘을 JSON 형태로 작성한다. JSON 객체를 base64 방식으로 인코딩하면 JWT의 Header가 완성된다. base64 방식은 디코딩할 수 있는 인코딩 방식으로 비밀번호와 같이 민감한 정보는 담지 않아야 한다.
{
"alg": "HS256",
"typ": "JWT"
}
Payload
Payload는 전달하려는 내용물을 담고 있는 부분으로, 어떤 정보에 접근 가능한지에 대한 권한과 유저의 이름과 같은 개인정보, 토큰의 발급 시간 및 만료 시간 등의 정보들을 JSON 형태로 담는다. JSON 객체를 base64로 인코딩하면 JWT의 Payload가 완성된다.
{
"sub": "information",
"name": "jungmin",
"iat": 151623721
}
Signature
Signature는 토큰의 무결성을 확인할 수 있는 부분으로 서버의 비밀 키(암호와에 추가할 salt)와 Header에서 지정한 알고리즘을 사용하여 해싱한다. Payload를 변조하는 등의 시도를 하더라도 토큰을 발급할 때 사용한 secret을 정확하게 알고 있지 않다면 서버는 Signature를 검증하는 단계에서 올바르지 않은 토큰을 알 수 있다.
HMACSHA256(base64UrlEncode(header) + '.' + base64UrlEncode(payload), secret);
무상태성
인증 상태를 관리하는 주체가 서버가 아니므로, 토큰이 탈취되어도 해당 토큰을 강제로 만료시킬 수 없다. 토큰이 만료될 때까지 사용자로 가장해 계속해서 요청을 보낼 수 있다.
유효 기간
토큰이 탈취되는 상황을 대비하기 위해서 유효 기간을 짧게 설정한다면, 사용자는 토큰이 만료될 때마다 다시 로그인을 해야하므로 좋지 않은 사용자 경험을 제공한다. 반대로 유효 기간을 길게 설정한다면 토큰이 탈취될 수 있는 문제가 발생될 수 있다.
토큰의 크기
토큰에 여러 정보를 담을 수 있으며 많은 데이터를 담을 경우에는 암호화하는 과정도 길어지고 토큰의 크기도 커지게 되며 네트워크 비용 문제가 생길 수 있다.
토큰 인증 한계를 극복하기 위한 대표적인 구현 방법으로 액세스 토큰과 리프레시 토큰을 함께 사용하는 방법이다.
Access Token
액세스 토큰은 서버에 접근하기 위한 토큰이며 보안을 위해서 보통 24시간 정도의 짧은 유효기간이 설정되어 있다.
Refresh Token
액세스 토큰이 만료되었을 때 새로운 액세스 토큰을 발급받기 위해 사용되는 토큰이며 액세스 토큰보다 긴 유효기간을 설정한다. 두가지의 토큰을 사용하면, 액세스 토큰이 만료되었어도 리프레시 토큰의 남은 유효기간동안 사용자는 재로그인을 하지 않아도 지속해서 인증 상태를 유지할 수 있다. 하지만 리프레시 토큰은 긴 유효 기간으로 사용자의 정보가 해킹될 수 있다는 문제가 발생할 수 있으므로 리프레시 토큰을 세션처럼 서버에 저장하고 상태를 관리하기도 한다.
⭐ 세션, 토큰 등 다양한 보안 방식 및 여러 구현 방법들에 완벽한 보완 방법은 없으며 보안과 사용자 경험 사이의 적절한 균형을 찾는 것이 중요하다!
전통적으로 직접 작성한 서버에서 인증을 처리해주는 것이 아니라, OAuth는 인증을 중개해주는 메커니즘이다. 보안된 리소스에 액세스하기 위해 클라이언트에게 권한을 제공하는 프로세스를 단순화하는 프로토콜이다.
이미 사용자 정보를 가지고 있는 웹 서비스에서 사용자의 인증을 대신해주고, 접근 권한에 대한 토근을 발급한 후, 이를 이용하여 내 서버에서 인증이 가능해진다. 웹이나 앱에서 사용하는 소셜 로그인 인증 방식은 OAuth 2.0의 기술을 바탕으로 구현된다.
➡소셜 로그인이 보편화되면서 대부분의 사람들은 이미 가입된 계정(네이버, 카카오, 구글 등)을 이용하여 빠르게 서비를 가입하는 것을 택하고 개발자도 회원 관리에 많은 신경을 쓰지 않아도 되고 보안상의 이점도 있어서 선호하고 있는 추세이다
▷ 쉽고 안전하게 새로운 서비스를 이용할 수 있다.
사용자는 회원 정보를 별도로 입력하지 않아도 OAuth를 통해서 클릭 몇 번으로 가입할 수 있는 편리함이 있다. 정보를 해당 서비스에 직접 노출하지 않으므로 직접 가입하는 것보다 안전하며 Application의 입장에서도 회원 정보 유출의 위험성에서 부담을 덜 수 있다.
▷ 권한 영역을 설정할 수 있다
OAuth 인증을 허가했어도 새로운 서비스가 사용중이던 서비스의 모든 정보에 접근이 가능한 것이 아니며 사용자가 원하는 정보에만 선택적으로 접근을 허락할 수 있어 더 안전하다.
OAuth의 주체
▷ Resource Owner (사용자)
OAuth 인증을 통해 소셜 로그인을 사용하고 싶어하는 사용자를 말하며 사용자의 이름, 전화번호 등 정보의 주인이다.
▷ Resource Server & Authorization Server (사용중인 서비스)
사용자가 소셜 로그인을 하기 위해서 사용 중인 서비스의 서버 중 사용자의 정보를 정하고 있는 서버를 Resource server라고 한다.
이미 사용 중인 서비스의 서버 중 인증을 담당하는 서버를 Authorization Server라고 한다.
▷ Application
사용자가 소셜 로그인을 활용하여 이용하는 새로운 서비스이며 Application을 Client와 Server로 경우에 따라서 세분화하기도 한다.
Implicit Grant Type
Implicit Grant Type은 서비스에 로그인 되어있을 경우에 액세스 토큰을 내어주므로 보안성이 떨어지는 부분이 있어서 잘 사용하지는 않는다.
Authorization Code Grant Type
Implicit Grant Type에서 Authorization Code를 사용한 인증 단게가 추가되었으므로 비교적 더 안전하게 사용할 수 있다. Application의 Client에 노출시키지 않고 Server에서만 관리하도록 만들 수도 있다.
Refresh Token Grant Type
액세스 토큰이 만료되면 위의 과정들을 거쳐서 다시 발급받아야 하므로 사용자 편의성에 좋지 않게 된다. 액세스 토큰이 발급될 때 리프레시 토큰을 같이 발급해주고 리프레시 토큰을 사용해서 액세스 토큰을 받아오는 인증 방식이다.
OAuth 참고자료
https://www.oauth.com/oauth2-servers/getting-ready