앞전 글에서 세션,토큰,OAuth에 대해 설명을 했는데 JWT도 정리 안하고 가면 JWT가 서운해 할 것 같아서 정리를 한번 해보려고 합니다 !
JWT는 JSON Web Token의 약자로 인증에 필요한 정보들을 암호화시킨 토큰을 말합니다. JWT 기반 인증은 쿠키/세션과 유사하게 Access Token을 HTTP 헤더에 실어 서버가 클라를 식별합니다.
JWT를 생성하기 위해서는 Header, Payload, Verify Signature 객체를 필요로 합니다.(즉 Header,Payload,Signauture로 이루어져 있다고도 할 수 있죠)
✅ 구조 (점 . 으로 나뉨)
이미지 순서대로 Header -> Payload -> Signature 로 나뉘어집니다 !
진~짜 간단하게 보면
Header : 이 토큰이 어떤 형식인지, 어떻게 암호화됐는지 설명
Payload : 실제 데이터가 들어감, 사용자 데이터 등이 담겨있음
Signature : 앞의 두 부분이 정상적인지 검증하는 용도
Header는 토큰의 타입을 나타내는 typ
과 암호화할 방식을 정하는 alg
로 구성되어 있습니다.
{
'alg': 'HS256',
'typ': 'JWT'
}
payload
는 실제로 토큰에 담을 정보를 지니고 있습니다.
주로 클라이언트 고유ID, 유효 기간, 발급 일시, 발급자, 권한정보 등이 포함되어 있습니다.
여기서 하나의 정보 조각을 Claim
으로 부릅니다. key-Value
형식으로 이루어진 한 쌍의 정보이죠
{
'sub': '1234567890',
'name': 'John Doe',
'admin': true,
'iat': 1516239022
}
Signature는 인코딩된 Header와 Payload를 더한 뒤, 비밀키로 해싱하여 생성합니다
Header 및 Payload는 단순 인코딩된 값이기 때문에 해커가 복호화하고 조작할 수 있지만, Signature는 서버 측에서 관리하는 비밀키가 유출되지 않는 이상 복호화할 수 없습니다..
따라서 Signature는 토큰의 위변조 여부를 확인하는 데 사용됩니다.
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret_key
)
Header, Payload는 인코딩될 뿐, 따로 암호화되지 않습니다. 따라서 Header, Payload는 누구나 디코딩하여 확인할 수 있기에 정보가 쉽게 노출될 수 있습니다. 하지만 Verify Signature는 SECRET KEY를 알지 못하면 복호화할 수 없습니다.
만약에 해커가 사용자의 토큰을 훔쳐 Payload의 데이터를 변경하여 토큰을 서버로 보낸다면, 서버에서 Verify Signature을 검사하게 됩니다.
여기서 Verify Signature는 해커의 정보가 아닌 사용자의 정보를 기반으로 암호화되었기 때문에 해커가 변경한 정보로 보낸 토큰은 유효하지 않은 토큰으로 간주합니다. 이를 통해 사용자의 SECRET KEY를 알지 못하면 토큰을 조작할 수 없다는 것을 알 수 있습니다.
Header와 Payload를 가지고 Signature를 생성하므로 데이터 위변조를 막을 수 있다.
인증 정보에 대한 별도의 저장소가 필요 없다.(빠르고 가벼움)
JWT는 토큰에 대한 기본 정보와 전달할 정보 및 토큰이 검증됐음을 증명하는 서명 등 필요한 모든 정보를 자체적으로 지니고 있다.
토큰 기반으로 다른 로그인 시스템에 접근 및 권한 공유가 가능하다. 즉 확장성이 뛰어나다 (OAuth + JWT 조합)
인증 정보에 대한 별도의 저장소가 필요 없다. (I/O 처리 필요 없음)
추가설명 )세션은 사용자가 로그인 하면 서버가 사용자 정보를 세션 저장소(메모리나 DB)에 저장 -> 그걸 계속 들여다보며 확인 -> 매 요청마다 저장소를 들여다보는 작업(I/O)필요함.
I/O는 디스크나 메모리 등에서 데이터를 읽고 쓰는 작업을 뜻함
반면 JWT는 로그인하면 서버는 토큰만 생성해서 클라이언트에게 제공 -> 그 안에 사용자 정보와 서명이 담겨있음 -> 사용자가 다시 요청할 때 이 토큰만 따악 보여주면 끝 !
클라의 인증 정보를 저장하는 세션과 달리(세션 방식은 로그인하면 서버가 누구인지 기억함), 서버는 무상태가 된다
추가설명) 서버가 로그인 상태를 기억하지 않아도 된다는 뜻이다. 즉 첫 로그인떄부터 JWT 토큰만 서버가 클라이언트에게 넘겨준 후 다음부터는 클라이언트가 "내가 누군지는 여기 써있어!"하며 JWT를 보여주며 서버는 아무것도 기억 안해도 인증 가능)
쿠키, 세션과 다르게 JWT는 토큰의 길이가 길어, 인증 요청이 많을수록 네트워크 부하가 심해진다.
Payload 자체는 암호화되지 않기 때문에 유저의 중요한 정보는 담을 수 없다. (패스워드 등)
토큰을 탈취당하면 대처하기 어렵다. 토큰은 한 번 발급되면 유효기간이 만료될 때까지 계속 사용이 가능하다.
특정 사용자의 접속을 강제로 만료하기 어렵다. (쿠키/세션 기반 인증은 서버 단에서 쉽게 삭제할 수 있지만 토큰은 그게 안 됨)
🤔 이러한 단점들 때문에 보완하기 위한 전략이 있습니다 !
토큰의 만료 기한을 짧게 설정해서 탈취되더라도 빠르게 만료시키는 방법입니다.
하지만 이는 토큰이 만료되면 사용자가 다시 로그인해야 한다는 뜻이기에 사용자 입장에서 번거로운 방법..
서비스를 지속적으로 이용하는 클라이언트에게 자동으로 토큰 만료 기한을 늘려주는 방법입니다.
사용자가 활동 중이라면 = "아직 살아있는 유저"라고 판단
토큰 만료 시간을 연장해줌
그래서 로그아웃되거나 재로그인하는 불편함이 줄어듦
클라이언트가 로그인할 때 Access Token 및 Refresh Token을 발급해주는 방법입니다.
Refresh Token은 Access Token보다 만료 기한이 긴 토큰입니다.
클라이언트가 요청을 보냈는데 Access Token이 만료되었을 때, Refresh Token을 이용하여 Access Token의 재발급을 요청합니다.
이때 서버는 DB에 저장된 Refresh Token과 비교하여 유효하면 Access Token을 발급을 합니다. 만약 Refresh Token도 만료된 경우라면 사용자에게 로그인을 요구합니다.
이 전략의 장점은?
하지만 이렇게 완벽하게 보이는 Refresh Token 발급 방법도 단점은 있다.