토큰은 웹 보안에서 인증과 권한 정보를 담고 있는 암호화된 문자열을 말한다.
토큰 인증 방식은 기존의 세션 기반 인증이 가지고 있던 한계를 극복하고자 고안되었다. 토큰을 사용하면 사용자의 인증 정보를 서버가 아닌 클라이언트 측에 저장할 수 있다.
유저의 인증 상태를 클라이언트에 저장할 수 있어서, 세션 인증 방식의 비교해 서버의 부하 또는 메모리 부족 문제를 줄일 수 있다.
서버가 유저의 인증 상태를 관리하지 않는다. 서버는 비밀 키를 통해 클라이언트에서 보낸 토큰의 유효성만 검증하면 되기 때문에 무상태적인 아키텍처를 구축할 수 있다.
다수의 서버가 공통된 세션 데이터를 가질 필요가 없다는 것도 토큰 기반 인증의 장점이다. 서버를 확장하기 더 용이하다.
토큰의 생성과 검증이 하나의 서버에서 이루어지지 않아도 되기 때문에 토큰 생성만을 담당하는 서버를 구축할 수 있다. 이를 활용하면 여러 서비스 간의 공통된 인증 서버를 구현할 수 있다.
토큰은 인증 상태, 접근 권한 등 다양한 정보를 담을 수 있기에 사용자 권한 부여에 용이하다. 이를 활용해 어드민 권한 부여 및 정보에 접근할 수 있는 범위도 설정 가능하다.
토큰 기반 인증 구현 시 대표적으로 사용되는 기술이다. JWT(JSON Web Token)는 JSON 객체에 정보를 담고 이를 토큰으로 암호화하여 전송할 수 있는 기술이다.
클라이언트가 서버에 요청을 보낼 때, 인증정보를 암호화된 JWT 토큰으로 제공하고, 서버는 이 토큰을 검증하여 인증정보를 확인할 수 있다.
.
으로 나누어진 세부분이 존재하며 Header
, Payload
, Signature
로 나뉜다.
헤더에는 HTTP의 헤더처럼 해당 토큰 자체를 설명하는 데이터가 담겨있다. 토큰의 종류, 그리고 시그니처를 만들 때 사용한 알고리즘을 JSON 형태로 작성한다.
{
"alg": "HS256",
"typ": "JWT"
}
JSON 객체를 base64 방식으로 인코딩하면 JWT의 첫 번째 부분인 헤더가 완성된다. 주의할 점은 비밀번호와 같이 노출되어서 안 되는 민감한 정보를 담지 않아야 한다.
HTTP의 페이로드와 마찬가지로 전달하려는 내용물을 담고 있다. 어떤 정보에 접근 가능한지에 대한 권한,
유저의 이름과 같은 개인정보, 토큰의 발급 시간 및 만료 시간 등의 정보를 JSON 형태로 담는다
{
"sub": "someInformation",
"name": "phillip",
"iat": 151623391
}
// base64로 인코딩하면 JWT의 두번 째 부분 Payload가 완성된다.
시그니처는 토큰의 무결성을 확인할 수 있다. 헤더와 페이로드가 완성되었다면, 시그니처는 이를 서버의 비밀 키(암호화에 추가할 salt)와 헤더에서 지정한 알고리즘을 사용하여 해싱한다.
누군가 권한을 속이기위해 토큰의 페이로드를 변조하는 등의 시도를 하더라도 토큰을 발급할 때 사용한 Secret을 정확하게 알고 있지 못하면 유효한 시그니처를 만들어낼 수 없기에 서버는 시그니처를
검증하는 단계에서 올바르지 않은 토큰임을 알아낼 수 있다.
시그니처를 사용해서 위조된 토큰을 알아낼 수는 있지만, 토큰 자체가 탈취된다면 토큰 인증 방식의 한계가 드러난다.
인증 상태를 관리하는 주체가 서버가 아니므로, 토큰이 탈취되어도 해당 토큰을 강제로 만료시킬 수 없다. 따라서 토큰이 만료될 때까지 사용자로 가장해 계속해서 요청을 보낼 수 있다.
토큰이 탈취되는 상황을 대비해 유효 기간을 짧게 설정하면, 사용자는 토큰이 만료될 때마다 다시 로그인을 진행해야 하기에 좋지 않은 사용자 경험을 제공한다.
반대로 유효 기간을 길게 설정하면 토큰이 탈취될 경우 더 치명적으로 작용할 수 있다.
토큰에 여러 정보를 담을 수 있는 만큼, 많은 데이터를 담으면 그만큼 암호화하는 과정도 길어지고 토큰의 크기도 커지기 때문에 네트워크 비용 문제가 생길 수 있다.
토큰 인증의 한계를 대비하기 위해 이 토큰을 함께 사용하는 방법이 생겨났다.
액세스 토큰은 서버에 접근하기 위한 토큰으로 보안을 위해 보통 24시간 정도의 짧은 유효기간이 설정되어 있다.
리프레시 토큰은 서버 접근을 위한 토큰이 아닌 액세스 토큰이 만료되었을 때 새로운 액세스 토큰을 발급받기 위해 사용되는 토큰이다. 따라서 리프레시 토큰은 액세스 토큰보다
긴 유효기간을 설정한다.
두 가지의 각기 다른 토큰을 사용하는 경우, 액세스 토큰이 만료되더라도 리프레시 토큰의 유효기간이 남아있다면 사용자는 다시 로그인을 할 필요없이 지속해서 인증 상태를 유지할 수 있다.
물론 이런 방법들이 보안에 있어 확실하지는 않다. 그렇기에 내가 구현하려는 서비스에 어떤 인증 방식이 가장 적절한지 판단하고 의사결정을 해야하는 것이 중요하다.