SW개발/IT 용어

[JWT]JWT 사용시 주의할 점 & 문제점

안녕하세요, 오늘은 지난번 포스팅에 이어 JWT를 무턱대고 사용할 때 생기는 문제점과 주의해야할 점들에 대해서 이야기 해보겠습니다.

 

JWT 사용시 주의할 점

시크릿 키의 설정

JWT의 가장 핵심적인 부분은 시크릿키에 대한 설정입니다. 해당 값을 알아낸다면 토큰을 생성하고 변조하여 악의적인 행동이 모두 가능해집니다. 따라서 시크릿 키만큼은 안전하게 설정할 필요가 있습니다.

 

시크릿 키의 경우 최소 512 bits 이상의 값을 설정하는 것을 권장합니다.

문자의 길이가 짧고 쉬울수록 브루트포스 어택에 굉장히 취약합니다. 특히, password / secret-key / my-secret 과 같이 유추하기 쉬운 문자의 경우에는 더욱 취약합니다. 따라서, Auto0 에서는 브루트포스 어택에 대비해 512 bits(약 64글자) 이상으로 시크릿 키를 설정하는 것을 권장하고 있습니다.


https://auth0.com/blog/brute-forcing-hs256-is-possible-the-importance-of-using-strong-keys-to-sign-jwts/

 

Brute Forcing HS256 is Possible: The Importance of Using Strong Keys in Signing JWTs

Cracking a JWT signed with weak keys is possible via brute force attacks. Learn how Auth0 protects against such attacks and alternative J...

auth0.com

 

시크릿 키는 코드상에 적기 보다는 환경변수와 같은 방식을 통해 안전하게 보관합니다.

다른 키 값들을 보관하는 방법과 동일합니다. JWT의 시크릿 키 역시 코드상에 문자열로 적기보다는 환경변수와 같은 방법을 이용해 키를 손쉽게 확인할 수 없도록 해야합니다.

 

중요한 데이터는 제외

JWT는 단순하게 보자면 Base64URL로 이루어진 문자열입니다. 따라서 디코딩만 한다면 토큰에 어떤 정보들이 들어있는지 바로 파악이 가능합니다. 따라서, 민감하거나 중요한 데이터는 포함하지 않아야 합니다.

 

Signature 검증에 대한 우회

최신 JWT 라이브러리를 사용한다면 크게 고려하지 않아도 되는 부분입니다. 다만 직접 구현하는 경우라면 주의해야 할 부분들이 있습니다.

JWT 토큰을 검증할 때는 단순히 디코딩하여 데이터를 확인하면 안되고, Signature와 시크릿 키를 이용해 데이터를 복호화 하고 변조되지 않았는지 검증을 필수적으로 해야합니다.

 

또한, alg 영역에서의 None으로 설정할 경우에 대한 취약점도 존재하므로 None을 할당하지 않는 것도 주의해야 합니다.

 

JWT 사용시 발생하는 문제점과 해결책

Stateless - 서버는 토큰에 대한 제어권이 없음

JWT는 서버의 부하를 줄이기 위해 탄생한 방법이므로 태생적으로 Stateless 입니다. 따라서, 한번 발급된 토큰이 발급되면 서버는 해당 토큰에 대한 제어권을 상실하게 됩니다.

 

이에 대한 문제점을 해결하기 위해 일반적으로 통용되는 해결책은 다음과 같습니다.

 

토큰의 만료시간을 설정

JWT 토큰의 만료 시간을 설정하여 특정 시점 이후로는 토큰이 이용될 수 없도록 합니다. 만료시간을 긴 주기로 가져가는 것 보다는 짧은 주기로 가져가는 것이 피해가 발생했을 때 그 크기를 최소화 할 수 있습니다.

 

하지만, 토큰의 만료시간을 짧게 설정한다면 그만큼 다시 발급을 받아야하니 번거롭겠죠? 예를 들어 만료시간을 5분으로 정한 경우, 사이트에서 5분마다 재 로그인을 해야하는 상황이 발생합니다. 그래서 Access TokenRefresh Token이 생겨났습니다.

 

Access Token, Refresh Token 두개로 운용

위에서 발생하는 문제점을 해결하기 위한 방법입니다. 바로 두 종류의 토큰을 운용하는 것입니다.

Access Token은 실제로 인증을 하는 용도로 사용을 합니다. Refresh TokenAccess Token이 만료 되었을 때 새로 발급을 하는 용도로만 제한하여 사용합니다.

 

예시와 함께 보겠습니다.

Access Token 1시간, Refresh Token 2주의 만료시간을 가지는 것으로 설정합니다. 이렇게 한다면 Refresh Token 값을 이용해 1시간마다 새로운 Access Token으로 교체하여 사용할 수 있습니다. Refresh Token 또한 만료된다면 그때에는 새롭게 두 토큰을 모두 갱신 받으면 됩니다. (비즈니스와 도메인 상황에 맞추어 적절히 주기를 조정하는 것이 좋습니다)

 

암호화 알고리즘의 설정

일반적으로 JWT 라이브러리에서 사용하는 암호화 라이브러리 기본 값은 "HS256 (HMAC with SHA-256)" 입니다. 즉, 대칭키 형식의 암호화 알고리즘으로서, 시크릿 키가 암/복호화에 모두 사용됩니다. 

 

이말은 시크릿 키가 만약에 탈취된다면 자유롭게 토큰을 생성하고 변조가 가능하다는 이야기입니다. 따라서 상대적으로 비대칭키(공개키) 방식보다 안전하지 않을 수 있습니다.

 

따라서 "RS256"과 같은 비대칭키 암호화 알고리즘을 사용하는 것도 하나의 방법이 될 수 있습니다. 공개키는 탈취되어도 프라이빗 키를 모르면 공격자는 할 수 있는 것이 없습니다. 다만, 두 알고리즘 간에는 Trade Off가 존재하므로 특징을 잘 살펴본 후에 상황에 맞게 적절하게 선택하는 것이 좋겠습니다.

 

마치며

이번에는 JWT 사용시에 주의할 점과 해결책들을 몇가지 알아보았습니다. 우선, 제가 적은 것 이외에도 JWT 토큰의 취약점이 더 많이 존재하고 해결책 또한 다양한 것들이 존재합니다.

 

항상 중요한 것은 상황에 맞는 적절한 선택입니다. 조직의 규모에 따라서 올바른 솔루션은 달라질 수 있습니다. 소규모의 조직이고 속도가 중요하다면 당장의 보안적인 비중을 조금 더 낮출수도 있고 이와 반대로 보안적인 요소가 중요한 조직이라면 긴밀하게 따져 보아야 할 것입니다.

 

여러가지 내용들을 살펴보면서 상황에 맞게 Trade Off가 최소화되는 방법들을 선택하시면 도움이 될 것 입니다.

 

긴 긁 읽어 주셔서 감사합니다 :)

 

728x90