All Articles

JWT를 알아보자

JYP 비슷한 엔터테인먼트 회사???

는 절대 아닙니다.

JWT 는 (JSON Web Tokken)의 줄임말이다.

HTTP 통신은 스테이트리스(stateless) 통신을 한다. 클라이언트의 상태(state)를 서버에 저장하지 않는다(less)라는 말이다. 서버 부담도 없어지고 좋은거 아니야? 라고 볼 수도 있지만 클라이언트가 로그인한 상태인지, 권한이 있는 유저인지 확인을 매 요청 시마다 확인을 해야 한다는 말이다. 이전의 인증 방식은 세션을 사용했다.

서버기반 인증(세션, Old Way)

유저가 로그인을 하게 되면, 서버측에서 유저가 현재 로그인 중이라는 인증정보를 기억하고 있어야 합니다. 그리고 이 정보를 세션 이라고 부릅니다.

세션을 유지하기 위해서는 여러가지 방법이 사용되는데, 메모리, 디스크, 데이터베이스 시스템에 이를 담곤 합니다. 하지만 이 시스템엔 몇가지 문제점이 있는데, 이 문제점들은 큰 규모의 어플리케이션을 개발하는 것에 있어서 걸림돌이 되곤 했습니다.

서버 기반 인증의 문제점

  1. 세션을 유지하게 될 때, 로그인중인 유저의 수가 많아진다면 성능에 무리가 가게 됩니다. 이 정보를 메모리에 넣게 된다면 램이 과부화가 되고, 데이터베이스에 넣게 된다면 데이터베이스의 성능에 무리가 가게 됩니다.
  2. , 서버 확장이 어려워진다는 점입니다. 여기서 서버 확장은, 단순히 서버의 사양을 업그레이드 하는 것 말고, 더 많은 트래픽을 감당하기 위하여 여러 프로세스를 돌리거나, 여러 서버 컴퓨터를 추가하여 로드밸런싱을 할때를 의미합니다. 세션을 사용하면서 분산된 시스템을 설계하는건, 세션의 정보가 분산된 프로세스간에 동기화가 되야하므로, 과정이 매우 복잡합니다.

그래서 클라이언트가 어느 상태에 있는지 증명하는 표식(Tokken)을 통해 증명한다. JSON(JavaScrpit Object Notation) 은 정보를 저장하는 포맷을 말한다. JWT는 Claim 기반이라는 방식을 사용하는데, Claim이라는 사용자에 대한 프로퍼티나 속성을 이야기 한다. 토큰자체가 정보를 가지고 있는 방식인데, JWT는 이 Claim을 JSON을 이용해서 정의한다.

Claim 기반의 토큰은 토큰 자체가 정보를 담음으로써, 토큰을 가지고 서비스나 API 접근을 제어할 때 별도의 작업이 서버에서 필요하지 않으며, 토큰 자체를 서버에서 관리할 필요가 없기 때문에 구현이 상대적으로 단순해진다.

JSON은 “\n”등 개행문자가 있기 때문에, REST API 호출시 HTTP Header등에 넣기가 매우 불편하다. 그래서, JWT에서는 이 Claim JSON 문자열을 BASE64 인코딩을 통해서 하나의 문자열로 변환한다.

토큰 기반 시스템이 제공해주는것은?

토큰 기반 시스템은 stateless 합니다. 이 용어의 의미는 ‘무상태’ 라는 뜻 인데요. 서버시스템측에서 더 이상 유저의 정보를 유지하지 않고, 유저가 회원 인증을 하게 될 때 토큰 을 발급해줌으로서 유저가 자기 자신임을 인증 할 수 있게 해줍니다. 발급이 된 토큰은, 토큰의 유효기간, 그리고 정보를 담고 있으며, 해싱 알고리즘을 통해 인증이 되어있어서 서버에서 검증을 통하여 처음 서버가 발급해주었던 정보가 변조되지 않았음을 보장 해 줄 수 있습니다.

  1. 토큰을 사용함으로서, 서버를 확장하게 될 때에 매우 용이해지게 됩니다. 서버 시스템이 분산이 되어있어도, 유저는 같은 토큰으로 서버에 요청을 하면 되고, 서버는 그저 그 토큰이 위조되지 않았는지만 검증을 하고 데이터베이스 조회도 할 필요 없이 바로 유저임을 신뢰하고 처리를 하면 되기 때문이죠.
  2. 추가적으로, 토큰을 사용하면 플랫폼간 권한을 공유 할 수 있습니다. 페이스북 / 구글 계정을 통한 소셜 로그인을 구현을 하는데, 이게 가능한 이유도 구글과 페이스북에서 토큰기반인증 시스템을 사용하기 때문입니다. 소셜 로그인 과정에서, 구글/페이스북 플랫폼에서 로그인을 하고, 해당 플랫폼이 토큰을 발급을 해주면 우리의 백엔드 서버에서 이를 통하여 회원정보를 가져오고 우리의 서비스에 계정 생성을 하게 됩니다.
  3. 마지막으로, 토큰 기반 시스템은 모바일 어플리케이션에서 사용하기에 편해집니다. 만약에 세션 기반 인증을 사용한다면, 쿠키를 사용해야 하기 때문에, 쿠키 매니저를 따로 관리해줘야 하지만, 토큰을 사용한다면 웹 요청 API 에 헤더에 넣어서 사용해주면 되기때문에 더이상 쿠키 매니저를 사용 할 필요가 없어집니다.

JWT 를 통해 발급된 토큰

  • header, payload, signature로 구성
  • header

    • alg : 사용한 알고리즘(암호화 하지 않았다면 none)
    • typ : 어떤 타입인지?
  • payload ( claim 내용 )

    • 담을 값, 표현이 정해져 있는 값들이 있다.
    • iss, sub, aud, exp, nbf, iat, jti
    • 그 외에 필요한 값들을 넣을 수 있다.
    • 주의사항
    • 페이로드정보는 secret key가 없어도 디코드가 가능하다.
    • 페이로드에 개별 식별 정보를 담을 수 있지만 영향력이 큰 정보는 담지 않는 편이 좋다. (특정 권한등의 표시 )
  • signature

    • 유효한 Token 인지 검증하는 부분이다.

JWT의 문제점

  1. 길이
  2. Claim에 넣는 데이터와 JWT 토큰의 길이는 비례한다. 클라이언트가 요청할 때마다 헤더에 토큰이 붙어 전송되므로, 네트워크 대역폭 낭비가 심하다.
  3. 한번 발급된 토큰 값의 수정 및 폐기 불가능
  4. JWT는 토큰 내에 모든 정보를 가지고 있어 한번 발급된 토큰을 서버가 변경할 수 없다. 그렇기 때문에 Reserved Claims에 expiration time을 꼭 지정해주고, refresh token 등을 통해 토큰을 재발급해주어야 한다.
  5. 보안
  6. 기본적으로 Claim을 암호화 하지 않고 단순히 base64 인코딩만을 하기 때문에 토큰이 타인에게 노출되면 사용자 정보가 유출될 수 있다.
  7. Payload에 권한과 관련된 Claim을 넣어 그 값으로만 사용자를 식별한다면 토큰 값 조작으로 인가되지 않은 접근 권한을 획득할 수 있다.

보안 고려사항

  1. Signature Stripping
  2. JWT 공격 방법 중 signature를 제거하는 것이 흔하다. 잘못된 검증으로 unsigned 상태인 토큰을 유효한 토큰으로 인식할 수 있으므로 애플리케이션에서 unsigned 토큰을 유효하지 않은 토큰으로 인식하도록 하면 된다.
  3. CSRF(Cross-Site Request Forgery)
  4. 토큰이 쿠키에 저장되는 경우, short-lived JWT를 이용하거나, origin 검증을 통해 CSRF 공격을 방어할 수 있다. 토큰이 쿠키에 저장되어있지 않으면 CSRF 공격은 불가능하다.
  5. XSS(Cross-Site Scripting)
  6. 액세스 토큰이 만료되기 전에 유출되면, 리소스에 접근하는 용도로 사용될 수 있다. 클라이언트에서 보낸 데이터를 반드시 sanitize 하고, 쿠키에 대해선 HttpOnly flag를 설정해 스크립트 코드로 접근하는 것을 막아야 한다.