JWT
기계적으로 DB에 접속해 반복적으로 read해오며 사용하다가 웹, DB호스팅을 하다 보니 웹에서 이루어지는 모든 통신은 돈이라는걸 깨닳았다. JWT에 대하여 고찰해보자.
JSON Web Token은 클라이언트의 정보를 JSON객체로 안전하게 전달하기 위한 개방형 표준이다.
객체에 클라이언트의 정보를 담아 암호화 알고리즘을 통해 키를 외부에서 접근하지 못하도록 암호화시킨 뒤 유통하는 것이 목적이다.
JWT를 사용하는 이유?
기존 웹페이지는 권한이 부여된 클라이언트인지 확인하기 위해서 SESSION 혹은 Cookie에 인증키값을 저장시킨뒤 허가가 필요한 정보에 대해 SESSION의 키 값으로 조회하여 승인을 내린다.
해당 방식은 Request에 대하여 지속적인 권한 조회가 필요하기 때문에 동시에 접속하는 인원이 많을수록 서버가 갖는 부담이 커지고 이는 Http의 장점인 Stateless를 위배한다. 반면 JWT는 권한 부여여부와 유효기간등의 정보를 미리 저장함으로 키에 대한 조회가 필요 없어 불필요한 서버통신을 부담하지 않을 수 있어 Stateless한 환경을 유지할 수 있다.
JWT의 구조
Json Web Token은 위와 같은 이유로 나타난 인터넷 표준 인증 방식이다.
인증이 이루어지는 방식은 Cookie와 유사하지만, JWT는 서명된 토큰으로 신뢰할 수 있다는 점이 강조되는 차이점이다. 공개/개인 키를 쌍으로 사용하여 개인 키를 보유한 사용자가 신뢰받는 사용자임을 증명한다. 이러한 JWT의 구조는 서버의 사용자 신뢰성을 높여줄 수 있다.
간단한 형태의 JSON 웹 토큰은 점( .)으로 구분된 세 부분으로 구성된다.
- Header
- Payload
- Signature
Header Payload Signature 따라서 JWT는 일반적으로 다음과 같다.
xxxxx.yyyyy.zzzzz
Header
토큰의 첫 번째 부분 Header는 토큰의 유형정보와 사용중인 Signature algorithm(ex:HMAC SHA256 또는 RSA)으로 구성된다.
Header의 예시 :
{
"alg": "HS256",
"typ": "JWT"
}
이 JSON은 Base64Url로 인코딩되어 JWT의 첫 번째 부분을 형성한다.
Payload
토큰의 두 번째 부분은 클레임을 포함하는 Payload이다. 클레임은 entity(일반적으로 클라이언트) 및 추가 데이터에 대한 설명이다. 클레임에는 1) 등록된 클레임, 2) 공개 클레임, 3) 비공개 클레임 세 가지 유형이 있다.
1) 등록된 클레임
필수는 아니지만 유용하고 상호 운용 가능한 클레임을 제공하기 위해 권장되는 미리 정의된 클레임 집합. 그들 중 일부는 iss (발급자), exp (만료 시간), sub (주제), aud (대상) 및 기타 이다.
2) 공개 클레임
JWT를 사용자의 임의대로 정의할 수 있다. 그러나 충돌을 방지하려면 IANA JSON 웹 토큰 레지스트리에 정의하거나 충돌 방지 네임스페이스를 포함하는 URI로 정의해야 한다.
3) 개인 클레임
사용에 동의한 당사자 간에 정보를 공유하기 위해 생성된 맞춤형 클레임이며 등록 또는 공개 클레임이 아니다.
Payload의 예시 :
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
이후 Payload는 Base64 Url로 인코딩 되어 JSON 웹 토큰의 두 번째 부분을 형성한다.
Signature
Signature 부분을 생성하려면 인코딩 된 Header, 인코딩된 Payload, secret, Header에 지정된 algorithm을 가져와서 서명해야 한다. 예를 들어 HMAC SHA256 알고리즘을 사용하려는 경우 서명은 다음과 같은 방식으로 생성됩니다.
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
Signature는 도중에 메시지가 변경되지 않았는지 확인하는 데 사용되며 개인 키로 서명된 토큰의 경우 JWT 발신자가 누구인지 확인할 수도 있다.
Putting all together
출력은 HTML 및 HTTP 환경에서 쉽게 전달할 수 있는 점으로 구분된 3개의 Base64-URL 문자열이며 SAML과 같은 XML 기반 표준과 비교할 때 더 작다. 다음은 이전 Header와 Payload가 인코딩 되고 암호로 서명된 JWT이다.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
JWT를 사용하고 이러한 개념을 실행하려는 경우 jwt.io 디버거를 사용하여 JWT를 디코딩, 확인 및 생성할 수 있다.
JWT의 보안이슈
위에서 주저리주저리 설명한 JWT를 간단하게 요약해 보자.
웹토큰 입장권의 기본 세팅값을 헤더에 적고 입장권 정보를 페이로드에 적은 뒤 BASE64로 인코딩 시킨 문자열이다.
Signature에는 secret password를 입력해 암호화할 수도 있다.
1. Algorithm의 암호화 여부
오래된 라이브러리나 개발 과정에서 Header의 Algorithm을 none으로 설정해 둔 경우가 있다.
해당 경우 악성유저가 알고리즘을 none으로 설정한 JWT를 서버로 날려보는 경우가 있는데 이 경우 서버에서 권한을 부여해 버리기 때문에 가장 기본적으로 유의해야 할 보안 사항이다.
2. JWT의 Decoding
JWT는 디코딩이 쉽기 때문에 유저정보가 유출될 수 있음을 상정하고, 민감한 정보를 Payload에 넣지 말아야 한다.
3. JWT의 유출
JWT가 유출된 경우, 토큰을 탈취한 사용자는 자유롭게 유출된 사용자의 정보를 사용할 수 있다. 이 경우 토큰을 유출시킨 사용자의 문제이지만 유출된 경우 후속조치가 불가능하다는 점이 JWT의 보안상 문제점이다.
JWT는 구조상 발급된 토큰을 해지시키는 것이 불가능하기 때문에 block 시킨 리스트를 따로 만들어 조회하는 방법을 이용해야 하는데 해당 방법을 이용하는 경우 결국 SESSION방식의 사용자 인증과 다른 점이 없어 JWT의 Stateless 한 장점이 사라진다.
Session을 대체하기 위해 나왔는데 결국 Session을 대체하지 못하는 것이다.
결론
결국 보안이 중요한 프로젝트에서는 단순히 JWT만으로 웹보안을 준수하기는 힘들고 보안을 위해 여러 번 고찰하고 Library를 사용하는 등 보안에 대한 여럿 대책마련이 필요하다. stateless 한 HTTP환경을 잃음에도 Session이 유구한 역사와 전통을 자랑하는 데는 결국 이유가 있나 보다.
REFERENCE
JWT.IO
JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.
jwt.io
'Backand > Java' 카테고리의 다른 글
[OOP] 객체 지향 프로그래밍 (0) | 2023.06.27 |
---|