제작년에 사내 블로그에 작성한 JWT 관련 포스팅을 개인 블로그로 옮겨 적어본다.
안녕하세요. 숨고에서 프론트엔드 개발을 하고 있는 Kei 입니다.
엔지니어 대부분 아는 척 하지만 제대로 알기 어려운 주제를 평소에 기록해 놓는 편인데 그중에 JWT 라는 키워드가 눈에 들어왔습니다. 이를 가지고 사내 기술세미나도 하고 정리도 해보면서 어느 정도 명확하게 개념을 파악했다 싶어 기술 블로그에 관련 내용을 공유 해볼까 합니다.
JWT가 무엇이냐 물어본다면 탄생 배경부터 득과 실, 활용예시, 연관기술 등 여러 가지를 이야기해 봐야겠지만 가장 단순하게 요약한다면 아래 그림이 맞습니다. JWT는 Header + Payload + Signature로 구성된 JSON Web Token 입니다.
위 그림은 JWT의 구조만을 묘사한것이어서 보다 명확한 기술적 정의를 파악하기 어렵습니다. 이런 내용을 포함하여 JWT를 웹표준의 명세로 정의할 수 있는데, JWT는 국제 인터넷 표준화 기구(Internet Engineering Task Force, IETF)에서 표준화한 Request for Comments 7519에 해당하는 명세 입니다. 이 명세에서 이야기하는 JWT는 결국 URL에서 사용이 가능하고 JSON이라는 편리한 자료구조를 포함하고 있으며 용량이 작고 대표적인 암호화 방식을 모두 지원하는 아주 괜찮은 녀석이라는 것입니다.
실제 활용 사례로 보면 JWT는 잘 만들어진 OAuth 2.0 인증에서의 Access Token 그 자체라고 할 수 있습니다. 잘 만들어진 이라는 수식어가 붙은 이유는 때에 따라서 JWT보다 보안이 취약한 형태의 Access Token을 사용할 수 있기 때문입니다. OAuth 2.0이라는 강력하고 유연한 인증 프로토콜에 Access Token 자체를 안전하고 의미 있게 만들어주는 JWT가 결합된다면 아주 괜찮은 선택이라 볼 수 있습니다.
뿐만아니라 JWT는 OAuth 2.0을 벗어나서 모든 Stringify Token에 적용할 수 있습니다.
세션은 유저의 상태를 저장할 수 있는 보편적인 기술 입니다. 다만 세션으로 인해 서버는 어쩔 수 없이 Session-Stateful 하게 운영할 수 밖에 없는데, 요즘 당연시 되고 있는 Scalable Architecture 입장에선 이것이적지 않은 비용을 야기합니다. 스케일링에서 발생하는 세션 데이터에 대한 데이터 불일치, 성능 등의 문제들 입니다.
스케일링 뿐만 아니라 Session-Stateful은 이를 참조하는 다른 자원에도 영향을 줍니다. 세션 데이터의 생성과 수정, 만료와 삭제에 따라 관계를 맺은 모든데이터 역시 동기화가 필요할 수 있겠지요. 세션 그 자체로 보아도 가만히 있는 상수가 아니고 지속적으로 변화되고 갱신되는 종류의 데이터 이기에 역시 유지보수 비용이 발생합니다.
Session-Stateful은 위 내용처럼 적잖은 비용의 원인이 될 수 있습니다. 개인적으로는 도메인, 비즈니스 데이터도 아닌 휘발성 데이터에 대해서 많은 비용을 쓰는것이 상당히 부담 스럽습니다.
JWT는 그 자체로 인증에 필요한 모든 요소를 갖췄기에 Session-Stateless한 아키텍쳐를 가능하게 합니다.
Session Stateful
Session Stateless
세션은 탄생 배경으로 보나 단순 접속 상태를 관리하는 기술적 관점으로보나 근본이 웹 기반의 기술 입니다. 애플리케이션의 백그라운드 상태, 비활성화, 자동 로그인 과 같이 다양한 Access Scope을 표현할 수 있는 모바일 디바이스에 적합한 접속 관리 방식이라 볼 수 없지요. JWT는 그 자체로 접근 권한을 포함하여 인증을 통과할 수 있기에 모바일 환경에서 적절히 세션을 대체할 수 있습니다.
JWT는 토큰의 타입과 해싱 알고리즘 방식을 규정하는 Header, Claim이라는 토큰의 여러 정보를 담아내는 Payload, 토큰의 유효성을 검증할때 필요한 Signature로 구성되어 있습니다.
이러한 정보는 본래에 JSON Format으로 존재하고 이를 각각 Base64 인코딩하여 마침표(dot)로 이어버리면 이렇게 URL Safe하고 여러 위치에서 활용 가능한 문자열 토큰이 완성됩니다.
Encoded JWT
아래 화면은 인코딩 이전의 JWT의 원형이 어떤 모양인지 대략 느껴볼 수 있는데 특히 Signature 부분을 주의해서 볼 필요가 있습니다. Signature는 Base64로 인코딩된 header와 payload를 비공개 키로 해싱한 결과값을 한번 더 Base64로 인코딩한 값입니다.
이러한 구조와 원리로 클라이언트에서 Encoded Token을 전송한 경우, 서버는 미리 알고 있는 비공개 키로 서명을 검증 함으로써 토큰의 유효성을 검증할 수 있고 클라이언트에서 요청한 데이터를 안전하게 응답할 수 있게 됩니다.
좌측 Encoded JWT, 우측 JWT 원래 데이터
JWT는 탄생 배경에서 언급한 Session Stateful, 여러 디바이스의 접속 상태 관리라는 측면에서 확실히 유리합니다. 또한 요즘 대부분의 인프라에서 활용하는 MSA(Micro Service Architecture)에서 그 진가를 발휘합니다. 무수히 많이 일어나는 서버간 통신에서 더이상 Stateful한 인증서버를 경유할 필요가 없기 때문입니다.
그럼에도 불구하고 JWT 역시 단점이 존재하고 제가 정리해본바는 다음과 같습니다.
제가 검토해본 결과 JWT는 클라이언트에겐 어느 정도 구현 복잡도를 위임하고 서버가 얻는 성능적, 유지보수 관점에서의 이득이 큽니다. 조직의 리소스와 상황에 맞게 적절히 검토하는편이 좋을것 같습니다. 또한 OAuth 2.0 구현을 고민한다면 어중간하게 의미없는 난수 String을 만드는 편 보단 Access Token을 JWT로 활용하시는편이 좋을것 같습니다.
그럼에도 불구하고 모든 인증문제와 보안은 기술 그 자체로 해결되긴 어렵습니다. 아래 통계는 대부분의 해킹과 공격이 내부자 문제로 발생하는것을 알 수 있습니다.
우린 모두 어떤 조직의 내부자 들이니 각별히 주의 하시어 고생해서 만든 인증-보안 시스템이 있음에도 불구하고 해킹과 공격으로 손해보는 일은 없었으면 합니다.
진짜 jwt 아는 척하고 다녔는데 이렇게 까지 제대로 알지 못했네요 ㅎㅎ 감사합니다~!