토큰 인증 방식으로 로그인을 구현한 웹 서비스에서 유저가 성공적으로 로그인하게 되면 JSON 형태의 웹 토큰을 반환하게 되고, 해당 토큰에는 Header, Payload, Signature 등의 내용이 포함되어 있어 이를 통해 유저 인가(Authorization)가 가능하다.
이를 통해 유저가 서버의 자원(Resource)을 생성, 업데이트, 삭제 등의 요청(Request)할 때 JWT를 요청 Header에 담아 요청을 보내고, 서버에서는 유효한 토큰인지 확인한 후 응답(Response)하게 된다.
JWT는 주로 사용자 인증 및 권한 부여에 사용되며, JSON 형식으로 클레임(claims)을 포함하는 토큰입니다. JWT는 세 가지 주요 부분으로 구성됩니다:
헤더(Header): 토큰 유형과 서명 알고리즘을 포함.
페이로드(Payload): 사용자 정보와 같은 클레임을 포함.
서명(Signature): 헤더와 페이로드의 내용을 기반으로 서명하여 데이터의 무결성을 검증합니다.
JWT 인증은 다음과 같은 장점이 있습니다.
JWT는 일반적으로 서명된 또는 암호화된 형태로 발행되지만,
몇 가지 보안 취약점이 존재할 수 있다:
JWT는 기본적으로 서명이 되어야 하지만, 실수나 설정 오류로 서명 없이 전송될 수 있다.
서명 없이 JWT가 전송되면 클라이언트나 공격자가 토큰을 변조가 가능하다.
예를 들어, 공격자는 페이로드를 수정하고 서버가 이를 확인하지 않으면
허가되지 않은 정보나 권한을 가진 사용자로 인증될 수 있음에 주의해야 한다.
JWT 서명에 사용되는 알고리즘을 "none"으로 설정할 수 있는데,
이는 실제 서명이 없이 토큰이 유효한 것으로 간주하게 된다.
만약 서버가 이를 제대로 검증하지 않으면,
공격자는 서명 없는 JWT를 생성하여 악용할 수 있다.
이와 같은 취약점은 알고리즘 다운그레이드(Algorithm Downgrade) 공격으로,
JWT 라이브러리에서 이를 방지하는 설정이 필요하다.
JWT는 만료 시간을 지정할 수 있지만,
만약 만료 시간이 지나치게 길다면 탈취된 JWT가 공격자가 사용 가능한 기간이 길어집니다.
적절한 만료 시간을 설정하지 않으면, 공격자는 토큰을 오랫동안 사용할 수 있습니다.
JWT는 보통 클라이언트 측(예: 브라우저의 localStorage나 sessionStorage)에 저장됩니다.
만약 클라이언트 측 저장소가 안전하지 않다면, 공격자가 이를 탈취할 수 있습니다.
예를 들어, XSS(교차 사이트 스크립팅) 공격을 통해 클라이언트 측 저장소에서 JWT를 탈취할 수 있습니다.
JWT는 기본적으로 서명만 제공하며, 데이터 자체는 암호화되지 않습니다.
따라서, 페이로드에 민감한 정보(예: 사용자 이메일, 역할 등)가 포함되면,
이를 쉽게 노출시킬 수 있습니다.
이를 방지하려면 JWT를 암호화해야 합니다.
예를 들어, 공격자가 JWT를 탈취하면 민감한 데이터를 쉽게 볼 수 있습니다.
JWT가 탈취되면 여러 가지 보안 사고를 초래할 수 있습니다.
탈취된 JWT가 악용될 수 있는 주요 문제는 다음과 같습니다:
JWT는 사용자 인증을 위한 증거로 사용되므로,
공격자가 탈취한 JWT를 사용하여 서버에서 인증을 우회할 수 있습니다.
예를 들어, 탈취된 JWT가 "관리자" 권한을 가지고 있다면,
공격자는 관리자 권한을 가진 사용자로 로그인하여 시스템에 접근할 수 있습니다.
만약 JWT의 페이로드에 사용자의 권한 정보(예: 역할 정보)가 포함되어 있다면,
공격자는 탈취한 JWT를 사용하여 권한을 상승시킬 수 있습니다.
예를 들어, 사용자가 "일반 사용자"로 설정된 JWT를 탈취했다면, 해당 JWT를 변조하여 "관리자" 권한을 얻을 수 있습니다. 이로 인해 시스템의 중요한 자원에 접근하거나 제어권을 얻을 수 있습니다.
JWT가 세션 토큰으로 사용되는 경우,
공격자는 이를 탈취하여 합법적인 사용자의 세션을 가로챌 수 있습니다.
이로 인해 공격자는 사용자로 가장하여 민감한 정보에 접근하거나
사용자의 권한으로 악의적인 행동을 할 수 있습니다.
JWT는 기본적으로 페이로드의 데이터를 암호화하지 않기 때문에, 페이로드에 민감한 정보가 포함되어 있다면 탈취된 토큰을 통해 이 정보가 유출될 수 있습니다.
예를 들어, 사용자의 이메일 주소나 신용 카드 정보가 JWT 페이로드에 포함되어 있다면, 이를 탈취한 공격자는 해당 정보를 악용할 수 있습니다.
탈취된 JWT를 이용하여 인증된 상태에서 서비스에 지속적인 요청을 보내거나,
공격자가 요청을 반복해서 보냄으로써 서버를 과부하 상태로 만들 수 있습니다.
JWT가 유효한 상태일 경우,
공격자는 유효한 요청을 반복해서 보내어 서비스에 영향을 줄 수 있습니다.
JWT의 보안을 강화하기 위한 몇 가지 방법은 다음과 같습니다:
JWT는 반드시 HTTPS로 전송하여, 중간에서 토큰이 탈취되지 않도록 해야 합니다.
NGINX Plus 지원 기능: NGINX Plus는 SSL/TLS를 통한 HTTPS 설정을 지원합니다.
이를 통해 JWT와 같은 민감한 데이터를 암호화된 채널을 통해 안전하게 전송할 수 있습니다.
실행 방법: NGINX Plus에서 SSL 인증서를 사용하여 HTTPS 연결을 설정할 수 있습니다.
이를 통해 모든 JWT 요청은 암호화된 상태로 전송되어 중간자 공격(MITM)으로부터 보호됩니다.
JWT의 만료 시간을 적절하게 설정하고, 만료된 JWT를 사용하지 않도록 합니다. 이를 통해 토큰 탈취 후 사용할 수 있는 시간을 제한할 수 있습니다.
location / { auth_jwt "Restricted Area"; auth_jwt_key_file /etc/nginx/keys/public_key.pem; auth_jwt_validate_expiry on; proxy_pass http://backend; }
NGINX Plus 지원 기능: NGINX Plus에서 JWT의 만료 시간을 검증하고, 만료된 토큰에 대한 접근을 차단할 수 있는 기능을 제공합니다. ngx_http_auth_jwt_module을 사용하면, 만료된 토큰을 요청할 때 인증을 거부할 수 있습니다.
실행 방법: NGINX Plus에서 JWT 토큰의 만료 시간(exp 클레임)을 검증하여 만료된 토큰에 대한 요청을 차단하도록 설정할 수 있습니다.
JWT의 서명 알고리즘을 안전하게 설정합니다. 가능한 한 강력한 알고리즘(예: RS256 또는 HS256)을 사용하고, "none" 알고리즘을 사용하지 않도록 해야 합니다.
NGINX Plus 지원 기능: NGINX Plus는 JWT 서명 검증을 수행할 수 있으며, 서명 알고리즘을 안전하게 설정하여 "none" 알고리즘을 사용할 수 없도록 강제할 수 있습니다.
실행 방법: JWT의 서명 알고리즘을 HS256, RS256 등으로 설정하고, NGINX Plus에서 서명 검증을 통해 무결성을 확인합니다.
location / { auth_jwt "Restricted Area"; auth_jwt_key_file /etc/nginx/keys/public_key.pem; auth_jwt_algorithm RS256; # RS256과 같은 안전한 알고리즘을 사용 proxy_pass http://backend; }
설명: auth_jwt_algorithm RS256을 설정하여 안전한 서명 알고리즘을 강제할 수 있습니다.
이를 통해 none 알고리즘 사용을 방지하고, JWT의 무결성을 확실히 검증할 수 있습니다.
민감한 정보를 JWT의 페이로드에 포함시킬 경우,
해당 정보를 암호화하여 토큰을 안전하게 만듭니다.
NGINX Plus 지원 기능
NGINX Plus는 기본적으로 JWT의 서명 검증 기능만 제공하며,
JWT 자체 암호화는 직접적으로 지원하지 않지만,
서명된 JWT를 사용하여 토큰이 변조되지 않았음을 확인할 수 있습니다.
민감한 정보를 안전하게 처리하려면,
백엔드 서버에서 추가적인 암호화를 수행하거나 JWT 암호화 기술을 적용해야 합니다.
실행 방법: JWT를 서버에서 암호화하여 전송하도록 구성하고,
NGINX Plus는 서명 검증을 통해 변조되지 않았음을 확인합니다.
클라이언트 측에서 암호화된 JWT를 관리하는 것도 좋은 방법입니다.
예시:
JWT를 암호화하여 클라이언트에 전송하고, 서버에서 이를 복호화한 후 사용.
NGINX Plus에서는 JWT의 서명 검증만 수행합니다.
JWT를 클라이언트 측 저장소에 보관할 때, XSS 및 CSRF 공격에 대비하여 적절한 보안 조치를 취합니다. 예를 들어, HttpOnly와 Secure 속성을 사용하는 쿠키에 JWT를 저장하는 방식도 고려할 수 있습니다.
NGINX Plus 지원 기능: NGINX Plus에서는 JWT를 쿠키에 저장하여 전달할 때, HttpOnly와 Secure 속성을 설정할 수 있습니다. 이를 통해 클라이언트 측 스크립트로부터 쿠키에 접근할 수 없도록 하여 XSS 공격을 방지할 수 있습니다.
실행 방법: JWT를 HttpOnly 및 Secure 속성을 설정한 쿠키에 저장하고, 이 쿠키를 통해 서버로 전달합니다. NGINX Plus에서는 쿠키에서 JWT를 추출하여 인증할 수 있습니다.
JWT가 탈취되어 반복적으로 사용될 경우를 대비해, API 요청에 대한 rate limiting을 설정하여 공격자가 JWT를 사용할 수 있는 횟수를 제한할 수 있습니다.
NGINX Plus 지원 기능: NGINX Plus는 Rate Limiting 기능을 제공하여, API 요청의 빈도를 제한할 수 있습니다. 이를 통해 탈취된 JWT가 반복적으로 사용되는 것을 방지할 수 있습니다.
실행 방법: NGINX Plus에서 limit_req와 limit_req_zone을 사용하여 요청 속도를 제한하고, 공격자가 탈취된 JWT를 사용할 수 있는 횟수를 제한합니다.