{{위키데이터 속성 추적}}
{{Infobox technology standard
| status          = [[인터넷 표준]]
| first_published = {{시작 날짜|2010|12|28}}
| version         = {{IETF RFC|7519}}
| version_date    = 2015년 5월
| organization    = [[국제 인터넷 표준화 기구|IETF]]
| abbreviation    = JWT
}}
'''JSON 웹 토큰'''(JSON Web Token, '''JWT''', "jot”<ref name="rfc7519">{{Cite IETF|title=JSON Web Token (JWT)|rfc=7519|last1=Jones|first1=Michael B.|last2=Bradley|first2=Bradley|last3=Sakimura|first3=Sakimura|date=May 2015|publisher=[[국제 인터넷 표준화 기구|IETF]]|doi=10.17487/RFC7519|issn=2070-1721}}</ref>)은 선택적 서명 및 선택적 암호화를 사용하여 데이터를 만들기 위한 인터넷 표준으로, 페이로드는 몇몇 클레임(claim) 표명(assert)을 처리하는 [[JSON]]을 보관하고 있다. 토큰은 비공개 시크릿 키 또는 공개/비공개 키를 사용하여 서명된다. 이를테면 서버는 "관리자로 로그인됨"이라는 클레임이 있는 토큰을 생성하여 이를 클라이언트에 제공할 수 있다. 그러면 클라이언트는 해당 토큰을 사용하여 관리자로 로그인됨을 증명한다. 이 토큰들은 한쪽 당사자의 비공개 키(일반적으로 서버의 비공개 키)에 의해 서명이 가능하며 이로써 해당 당사자는 최종적으로 토큰이 적법한지를 확인할 수 있다. 일부 적절하고 신뢰할만한 수단을 통해 다른 당사자가 상응하는 공개키를 소유하는 경우 이 경우 또한 토큰의 적법성 확인이 가능하다. [[세션 토큰|토큰]]은 크기가 작고<ref>{{서적 인용|last1=Nickel |first1=Jochen |title=Mastering Identity and Access Management with Microsoft Azure |date=2016 |isbn=9781785887888 |page=84 |url=https://books.google.com/books?id=Q4dcDgAAQBAJ&pg=PA84 |accessdate=20 July 2018}}</ref> [[URL]] 안전으로 설계되어 있으며<ref name="jwtintro" /> 특히 [[웹 브라우저]] [[통합 인증]](SSO) 컨텍스트에 유용하다.
JWT 클레임은 [[아이덴티티 제공자]]와 [[서비스 제공자]] 간(또는 비즈니스 프로세스에 필요한 클레임)의 인가된 사용자의 아이덴티티를 전달하기 위해 보통 사용할 수 있다.<ref>{{웹 인용|title = The Anatomy of a JSON Web Token|url = https://scotch.io/tutorials/the-anatomy-of-a-json-web-token|accessdate = 2015-05-08|first = Chris|last = Sevilleja}}</ref><ref>{{웹 인용|title = Atlassian Connect Documentation|url = https://developer.atlassian.com/static/connect/docs/latest/concepts/understanding-jwt.html|website = developer.atlassian.com|accessdate = 2015-05-08|archive-date = 2015-05-18|archive-url = https://web.archive.org/web/20150518082002/https://developer.atlassian.com/static/connect/docs/latest/concepts/understanding-jwt.html|url-status = }}</ref>

JWT는 다른 JSON 기반 표준에 의존한다: [[JSON 웹 시그너처]] 및 [[JSON 웹 암호화]].<ref name="rfc7519" /><ref name=":1">{{웹 인용|title = draft-ietf-jose-json-web-signature-41 - JSON Web Signature (JWS)|url = https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-41|website = tools.ietf.org|accessdate = 2015-05-08}}</ref><ref name=":2">{{웹 인용|title = draft-ietf-jose-json-web-encryption-40 - JSON Web Encryption (JWE)|url = https://tools.ietf.org/html/draft-ietf-jose-json-web-encryption-40|website = tools.ietf.org|accessdate = 2015-05-08}}</ref>

== 구조 ==
{| class="wikitable"
|-
!scope="row"| 헤더
| style="width: 22em;" |<syntaxhighlight lang="json">{
 "alg" : "HS256",
 "typ" : "JWT"
}
</syntaxhighlight>
|| 서명 생성을 위해 어느 알고리즘을 사용할지를 식별한다

<code>HS256</code>는 이 토큰이 HMAC-SHA256를 사용하여 서명됨을 의미한다.

일반적으로 쓰이는 암호화 알고리즘들은 [[SHA-2]](HS256) 방식의 [[HMAC]]와 SHA-256(RS256) 방식의 [[디지털 서명|RSA 서명]]이다. JWA(JSON 웹 알고리즘) RFC 7518은 인가 및 암호화를 위해 더 많은 것을 도입하고 있다.<ref>{{웹 인용|title = draft-ietf-jose-json-web-algorithms-40 - JSON Web Algorithms (JWA)|url = https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40|website = tools.ietf.org|accessdate = 2015-05-08}}</ref>
|-
!scope="row"| 페이로드
||<syntaxhighlight lang="json">{
 "loggedInAs" : "admin",
 "iat" : 1422779638
}
</syntaxhighlight>
|| 일련의 클레임을 포함한다. JWT 사양은 토큰에 일반적으로 포함되는 [[#표준 필드|표준 필드]]인 7개의 등록 클레임 이름(Registered Claim Names)을 정의한다.<ref name="rfc7519" /> 토큰의 목적에 따라 사용자 지정 클레임 또한 일반적으로 포함된다.

다음 예는 표준 Issued At Time 클레임(<code>iat</code>)과 사용자 지정 클레임(<code>loggedInAs</code>)을 보여준다.

|-
!scope="row"| 서명
||<syntaxhighlight lang="javascript">
HMAC-SHA256(
 secret,
 base64urlEncoding(header) + '.' +
 base64urlEncoding(payload)
)
</syntaxhighlight>
|| 토큰을 안전하게 확인한다. 서명은 [[베이스64|Base64url 인코딩]]을 이용하여 헤더와 페이로드를 인코딩하고 이 둘을 점(.) 구분자로 함께 연결시킴으로써 계산된다. 해당 문자열은 그 뒤 헤더에 규정된 암호화 알고리즘(이번 경우에는 HMAC-SHA256)에 유입된다. Base64url 인코딩은 [[베이스64|base64]]와 비슷하지만 각기 다른 영숫자를 사용하며 패딩(padding)은 제외한다.
|}

이 세 부분은 [[베이스64|Base64url 인코딩]]을 사용하여 별도로 인코딩되며 JWT 생성을 위해 점(.)을 사용하여 연결된다:
<syntaxhighlight lang="javascript">
const token = base64urlEncoding(header) + '.' + base64urlEncoding(payload) + '.' + base64urlEncoding(signature)
</syntaxhighlight>

위 데이터와 "secretkey" 시크릿은 토큰을 생성한다:
{{Pre2|scroll|eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsb2dnZWRJbkFzIjoiYWRtaW4iLCJpYXQiOjE0MjI3Nzk2Mzh9.gzSraSYS8EXBxLN_oWnFSRgCzcmJmMjLiuyu5CSpyHI}}

이 결과가 되는 토큰은 [[HTML]]과 [[HTTP]]로 쉽게 파싱이 가능하다.<ref name="jwtintro">{{웹 인용|title=JWT.IO - JSON Web Tokens Introduction |url=https://jwt.io/introduction/ |website=jwt.io |accessdate=20 July 2018}}</ref>

== 이용 ==
인증의 경우 사용자가 성공적으로 자신들의 자격 정보를 사용하여 로그인하면 서버에 세션을 만들고 쿠키를 반환하는 전통적인 접근방식 대신 JSON 웹 토큰이 반환되며 로컬(일반적으로 [[웹 스토리지|로컬 또는 세션 스토리지]]. [[HTTP 쿠키|쿠키]]를 사용할 수도 있음)에 저장되어야 한다. 부재 중인 프로세스의 경우 클라이언트는 미리 공유된 시크릿으로 자신만의 JWT를 생성하고 서명하고 이를 [[OAuth]]를 준수하는 서비스에 전달함으로써 다음과 같이 직접 인증을 수행할 수도 있다.:<syntaxhighlight lang="mime">
POST /oauth2/token?
Content-type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=eyJhb...
</syntaxhighlight>
클라이언트가 유효한 JWT 표명을 전달하면 서버는 애플리케이션의 요청을 하기 위한 access_token을 생성하고 클라이언트에 이를 전달해주게 된다:<syntaxhighlight lang="json">
{
  "access_token": "eyJhb...",
  "token_type": "Bearer",
  "expires_in": 3600
}
</syntaxhighlight>
클라이언트가 보호된 루트나 자원에 접근하고 싶은 경우 사용자 에이전트는 일반적으로 <code>Bearer</code> 스키마를 사용하여 <code>Authorization</code> 헤더 안에 JWT를 보내야 한다. 헤더의 내용은 다음과 같을 수 있다:
 Authorization: Bearer eyJhbGci''...&lt;snip&gt;...''yu5CSpyHI
이것은 무상태 인증 매커니즘으로서, 사용자의 상태는 서버 메모리에 전혀 저장되지 않는다. 서버의 보호된 루트는 Authorization 헤더 내의 유효한 JWT를 검사하며 이것이 존재하는 경우 사용자는 보호된 자원으로의 접근이 허가된다. JWT가 자가 수용적(self-contained)이므로 필요한 모든 정보는 JWT에 있으며 데이터베이스를 여러 번 조회할 필요를 줄여준다.

== 구현체 ==
JWT 구현체는 수많은 언어와 프레임워크용으로 존재한다:
{{colbegin|colwidth=20em}}
* [[닷넷 프레임워크|.NET (C# VB.Net 등)]]<ref>[https://github.com/jwt-dotnet/jwt jwt-dotnet] on [[깃허브]]</ref>
* [[C (프로그래밍 언어)|C]]<ref>[https://github.com/benmcollins/libjwt libjwt] on [[깃허브]]</ref>
* [[클로저 (프로그래밍 언어)]]<ref>{{웹 인용|url=https://github.com/liquidz/clj-jwt|title=liquidz/clj-jwt|website=GitHub|language=en|access-date=2018-05-07}}</ref>
* [[커먼 리스프]]<ref>[https://github.com/gschjetne/cljwt cljwt] on [[깃허브]]</ref>
* [[다트 (프로그래밍 언어)|Dart]]<ref>[https://github.com/deftomat/JustJWT] on [[깃허브]]</ref>
* [[Elixir]]<ref>{{웹 인용|url=https://github.com/bryanjos/joken|title=bryanjos/joken|website=GitHub|language=en|access-date=2018-05-07}}</ref>
* [[얼랭|Erlang]]
* [[Go (프로그래밍 언어)|Go]]<ref>{{웹 인용|url=https://github.com/dgrijalva/jwt-go|title=dgrijalva/jwt-go|website=GitHub|language=en|access-date=2018-01-08}}</ref>
* [[하스켈]]<ref>{{웹 인용|url=https://hackage.haskell.org/package/jwt|title=jwt: JSON Web Token (JWT) decoding and encoding|website=Hackage|access-date=2018-05-07}}</ref>
* [[자바 (프로그래밍 언어)|자바]]<ref>[https://github.com/auth0/java-jwt auth0/java-jwt] on [[깃허브]]</ref>
* [[자바스크립트]]<ref>{{웹 인용|url=https://github.com/kjur/jsrsasign|title=kjur/jsrsasign|website=GitHub|language=en|access-date=2018-05-07}}</ref>
* [[루아 (프로그래밍 언어)|루아]]<ref>{{웹 인용|url=https://github.com/SkyLothar/lua-resty-jwt|title=SkyLothar/lua-resty-jwt|website=GitHub|language=en|access-date=2018-05-07}}</ref>
* [[Node.js]]<ref>{{웹 인용|url=https://www.npmjs.com/package/jsonwebtoken|title=jsonwebtoken|website=npm|access-date=2018-05-07}}</ref>
* [[OCaml]]<ref>[https://github.com/besport/ocaml-jwt ocaml-jwt] on [[깃허브]]</ref>
* [[펄]]<ref>[https://metacpan.org/pod/Crypt::JWT Crypt::JWT] on [[CPAN]]</ref>
* [[PHP]]<ref>[https://github.com/lcobucci/jwt lcobucci/jwt] on [[깃허브]]</ref>
* [[PL/SQL]]<ref>{{인용|last=Egan|first=Morten|title=GitHub - morten-egan/jwt_ninja: PLSQL Implementation of JSON Web Tokens.|date=2019-02-07|url=https://github.com/morten-egan/jwt_ninja|access-date=2019-03-14}}</ref>
* [[파워셸]]<ref>{{웹 인용|url=https://github.com/SP3269/posh-jwt|title=SP3269/posh-jwt|website=GitHub|access-date=2018-08-01}}</ref>
* [[파이썬]]<ref>{{웹 인용|url=https://github.com/jpadilla/pyjwt|title=jpadilla/pyjwt|website=GitHub|language=en|access-date=2017-03-21}}</ref>
* [[래킷 (프로그래밍 언어)|래킷]]<ref>[https://pkgs.racket-lang.org/package/net-jwt net-jwt] on [[pkgs.racket-lang.org]]</ref>
* [[라쿠 (프로그래밍 언어)|라쿠]]<ref>[https://github.com/jamesalbert/JSON-WebToken JSON-WebToken] on [[깃허브]]</ref>
* [[루비 (프로그래밍 언어)|루비]]<ref>[https://github.com/jwt/ruby-jwt ruby-jwt] on [[깃허브]]</ref>
* [[러스트 (프로그래밍 언어)|러스트]]<ref>[https://github.com/GildedHonour/frank_jwt frank_jwt] on [[깃허브]]</ref><ref>[https://github.com/mikkyang/rust-jwt] on [[깃허브]]</ref>
* [[스칼라 (프로그래밍 언어)|스칼라]]<ref>[https://github.com/pauldijou/jwt-scala jwt-scala] on [[깃허브]]</ref>
* [[스위프트 (프로그래밍 언어)|스위프트]]<ref>[https://github.com/kylef/JSONWebToken.swift] on [[깃허브]]</ref>
{{colend}}

== 취약성 ==
JSON 웹 토큰은 세션 상태를 포함할 수 있다. 그러나 프로젝트 요건이 JWT 기간 만료 이전에 세션 무효화를 허용하는 경우 서비스는 더 이상 토큰만으로 토큰 표명(token assertion)을 신뢰할 수 없다. 토큰에 저장된 세션이 폐지되지 않음을 확인하기 위해 토큰 표명은 [[데이터 스토어]]에 대해 검사되어야 한다. 이렇게 하면 토큰이 더 이상 무상태가 아니게 됨으로써 JWT의 주된 이점이 약화되는 결과를 낳는다.<ref>{{웹 인용|last1=Slootweg |first1=Sven |title=Stop using JWT for sessions |url=http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-for-sessions/ |website=joepie91 Ramblings |accessdate=1 August 2018}}</ref>

보안 상담가 팀 메클레인(Tim McLean)은 <code>alg</code> 필드를 사용하여 토큰의 유효성을 잘못 확인하는 일부 JWT 라이브러리의 취약성을 보고하였다. 이 취약점들이 패치가 되었으나 메클레인은 비슷한 구현체 혼동을 예방하기 위해 <code>alg</code> 필드를 구식 처리하는 것을 제안하였다.<ref name=auth0>{{웹 인용|first=Tim |last=McLean | date=March 31, 2015 | title = Critical vulnerabilities in JSON Web Token libraries|url = https://www.chosenplaintext.ca/2015/03/31/jwt-algorithm-confusion.html|publisher=Auth0|accessdate = 2016-03-29}}</ref>

적절히 설계할 경우 개발자는 일부 주의를 기울이면 알고리즘 취약성을 해결할 수 있다:<ref name=vuln>{{웹 인용|url=https://connect2id.com/products/nimbus-jose-jwt/vulnerabilities|language=en|access-date=2018-05-14|title=Common JWT security vulnerabilities and how to avoid them}}</ref><ref>{{웹 인용|last1=Andreas |first1=Happe |title=JWT: Signature vs MAC attacks |url=https://snikt.net/blog/2019/05/16/jwt-signature-vs-mac-attacks/ |website=snikt.net |accessdate=27 May 2019}}</ref>

# JWT 헤더만으로 유효성을 확인하지 않을 것
# 알고리즘을 인지할 것
# 적절한 키 크기를 사용할 것

소프트웨어 보안 설계자 커트 로다머(Kurt Rodarmer)는 암호화 서명 키와 관련한 JWT의 추가적인 설계적 취약성, 그리고 라이브러리의 JSON 파서가 공격에 노출되는 중대한 취약성을 지적한다.<ref>{{웹 인용 | first = Kurt | last = Rodarmer | date = July 21, 2019 | title = Obscure JWT Security Vulnerabilities | url = https://rodarmer.squarespace.com/security-blog/2019/7/21/jwt-security-vulnerabilities | publisher = rodarmer.com | accessdate = 2019-07-25 | archive-date = 2019-07-25 | archive-url = https://web.archive.org/web/20190725113001/https://rodarmer.squarespace.com/security-blog/2019/7/21/jwt-security-vulnerabilities | url-status =  }}</ref> 이는 토큰 헤더를 표현할 때 JSON을 선택하는데 따른 직접적인 결과이며 완화가 어렵다.

== 같이 보기 ==
* [[기본 인증]]
* [[다이제스트 인증]]
== 각주 ==
{{각주}}

== 외부 링크 ==
* {{IETF RFC|7519}}
* [https://jwt.io/ jwt.io] – specialized website about JWT with tools and documentation, maintained by Auth0
* [http://www.devglan.com/spring-security/spring-boot-jwt-auth Spring Boot JWT Auth] – Integrating JWT authentication with Spring framework
* [https://sekurak.pl/jwt-security-ebook.pdf JWT Security] – JWT Security e-Book PDF (Polish language)
* [https://medium.com/swlh/why-do-we-need-the-json-web-token-jwt-in-the-modern-web-8490a7284482 Why do we need JWT in the modern web] - a detailed article on the topic with some historical considerations

[[분류:컴퓨터 접근 제어]]
[[분류:아이덴티티 관리]]
[[분류:아이덴티티 관리 시스템]]
[[분류:메타데이터 표준]]
[[분류:JSON]]