JWT(Json Web Token)
Json Web Token
Last updated
Json Web Token
Last updated
JWT 구조
JWT는 이렇게 ‘.
’ 을 기준으로 세부분으로 나뉜 Base64-URL 문자열이며 SAML과 XML 기반 표준과 비교해서 더 간결하다. header, payload가 인코딩되어있고 secret signed JWT를 나타낸다.
Header
Header는 토큰의 타입(typ)와 암호화에 사용된 알고리즘을 나타낸다. 그리고 이 JSON 형태는 Base64Url로 인코딩되어 JWT 첫번째 부분을 구성한다.
*secretKey* = Base64.*getEncoder*().encodeToString(*secretKey*.getBytes());
Payload
payload에서는 Claims를 포함한다. Claims는 entity(유저정보)에 대한 상태와 추가적인 정보들을 담고있다. claims에는 (1) registered, (2) public, (3) private claims 세가지 타입의 claims가 있다.
(1) registered claims
필수는 아니지만 권장되는 미리 정의된 클레임 집합이다.
그 중 일부는 iss (발행자), exp (만료 시간), sub (주제), aud (청중)등으로 구성되어 있다 .
(2) public claims
사용자가 원하는 대로 정의할 수 있다. 하지만 충돌을 방지하기 위해서 IANA JSON web token registry에 정의하거나 충돌 방지 네임스페이스를 포함하는 URI로 정의해야 한다.
(3) private claims
정보를 공유하기 위한 custom claims이다. 사용에 동의한 사용자, registered, public 을 제외한 claims이다.
Base64Url로 인코딩되어 JWT 두번째 부분을 구성한다.
Signature
signature를 생성하기 위해서는 encoded header, encoded payload, secret-key, 헤더에 들어갈 특정 알고리즘과 사인등이 필요하다.
ex) HMAC SHA256
signature은 메시지가 변조되었는지 확인하는데에 사용되며, token은 private key로 사인되어 JWT를 보낸사람이 누군지 증명하는데에 사용된다.
인증 시 사용자가 자격 증명을 사용해 성공적으로 로그인하면 JSON Web Token이 반환된다. 일반적으로 토큰을 필요한 것보다 오래 보관하면 안된다. 또한 민감한 데이터를 브라우저 저장소등에 보관하면 안된다. 사용자가 보호된 경로 혹은 리소스에 접근하려 할 때마다 일반적으로 Bearer 스키마를 사용해서 Authorization - header에 JWT를 보내야 한다.
Authorization : Bearer <token>
이 방법은 stateless 하며 인증이 필요한 경로/페이지 에서는 유효한 JWT를 인증을 확인하고 JWT가 인증이 되면 보호된 리소스에 접근이 가능하다. 또한 HTTP header를 통해 JWT를 보내는 경우 token이 너무 커지지 않도록 주의해야 한다. 일부 서버는 8KB 이상을 허용하지 않는 경우가 있다. 또 만약 너무 많은 정보를 포함해야 할 경우에는 Auth0 Fine-Grained Authorization
와 같은 방법을 모색해봐야 한다.
토큰이 Authorization 헤더로 전송되면 CORS(Cross-Origin-Resource Sharing)는 쿠키를 사용하지 않기에 문제가 되지 않는다.
JWT를 사용해서 접근이 제한된 리소스나 API 에 접근하려면 아래와 같은 순서도로 진행된다.
application이나 client에서 서버(혹은 권한 서버)에 인증을 요청한다.
인증이 되면 권한을 부여받고, 권한 서버는 토큰을 application/client로 돌려주게 된다.
application user는 protected resource(or API)에 접근하기 위해 access-token을 사용하게 된다.
Simple Web Tokens(SWT), Security Assertioin Markup Language Tokens(SAML)과 JWT를 비교해보자.
SAML의 경우에는 XML 형식이다. JSON형식의 JWT에 비해서 장황하기에 HTML이나 HTTP 환경에서 전달되기에 좋은 선택지는 아니다.
(보안측면에서) SWT는 HMAC 알고리즘을 사용하고 shared secret(공유키)를 통해서만 symmetrically 서명한다. 하지만 JWT와 SAML의 경우엔 public/private key pair를 사용할 수 있다.
JSON parser는 객체에 직접 매핑되기 때문에 대부분의 프로그램에서 일반적으로 사용된다. 반대로 XML에는 자연스러운 문서-객체 매핑이 없다. SAML보다는 JWT 작업이 더 간결하다고 볼 수 있다. 그렇기에 인터넷규모에서 모바일 등 여러 플랫폼에서 JWT를 사용한 클라이언트 측 처리 용이성이 쉬워지기에 JWT가 대중화 되었다고 볼 수 있다.
시크릿 키의 설정
문자의 길이가 짧을수록 브루트포스 공격에 취약함
최소 512 bit (64글자) 이상
환경변수와 같은 방식으로 안전하게 보관
중요한 데이터
JWT는 Base64URL로 이루어진 문자열. 따라서 decoding만 하면 token에 어떠한 정보들이 들어있는지 바로 파악이 가능함. 따라서 민감하거나 중요한 데이터는 직접적으로 포함하지 않아야 함
Signature 검증에 대한 우회
JWT 라이브러리를 사용한다면 크게 고려하지 않아도 됨.
하지만 직접구현하는 경우, JWT 토근을 검증할 때 단순히 디코딩해서 데이터를 확인하면 안되고, Signature와 Secret-key를 이용해 데이터를 복호화하고 변조되지 않았는지에 대한 검증을 필수로 해야함.
암호화 알고리즘 설정
JWT는 기본으로 HS256(HMAC with SHA-256) 알고리즘을 사용함. 대칭키로 시크릿키가 암/복호화에 모두 사용됨. secret-key가 탈취되면 암/복호화에 모두 취약해져 자유롭게 토큰을 생성하고 변조가능하다라는 단점이 있음.
RS256과 같은 비대칭키 암호화 알고리즘을 사용해 public-key가 탈취되더라도 private-key를 모르면 디코딩이 불가능하게 설계 가능.
참고 : JWT debugger :