JWT Penetration Test
Core JWT Vulnerability Analysis and Attack Scenarios
The majority of successful JWT attacks begin with a single objective: bypassing the server’s signature verification logic. If the signature can be nullified, an attacker can manipulate the token’s contents at will to deceive the server.
1. Signature Bypass: The alg:none
Attack
This is the most fundamental vulnerability and a mandatory first check.
- Overview: The attacker modifies the
alg
(algorithm) claim in the JWT header tonone
and submits the token with the signature part completely removed. If the server-side library is configured to accept this, it will skip the signature verification process and trust the contents of the payload implicitly. - Attack Scenario:
- Obtain a legitimate token and analyze its structure.
- Change the
alg
value in the header tonone
. - Remove the third part of the token, the signature.
- Send the manipulated token, now in the format
Header.Payload.
(including the trailing dot), to the server.
- Key Payload:
- Header Before:
{"alg": "HS256", "typ": "JWT"}
- Header After:
{"alg": "none", "typ": "JWT"}
- Header Before:
- Testing Method: Use a tool like Burp Suite’s JWT Editor or Repeater to manually manipulate the header and signature, then observe the server’s response. A 200 OK or another successful response indicates the vulnerability is present.
2. Algorithm Confusion Attack: From RS256 to HS256
This is a technically fascinating and high-impact attack. It involves tricking a server expecting an asymmetrically signed token (RS256) into processing a symmetrically signed one (HS256).
- Overview: The public key used to verify RS256 signatures is, by definition, public. An attacker can leverage this by using the public key as if it were a symmetric secret key for an HS256 signature. If the server does not strictly enforce the algorithm type, it will mistakenly use the public key as the secret key and validate the manipulated signature.
- Attack Scenario:
- Identify a token signed with the
RS256
algorithm. - Obtain the server’s public key. This can often be found at a public endpoint like
/.well-known/jwks.json
. - Manipulate the payload as desired (e.g., change the
role
toadmin
). - Change the
alg
value in the header fromRS256
toHS256
. - Using the public key obtained in step 2 as the secret key, generate a new HS256 signature for the manipulated header and payload.
- Send the completed forged token to the server.
- Identify a token signed with the
- Testing Method: After obtaining the public key, use a tool like CyberChef or a custom script to generate the HS256 signature and forge the token for testing.
3. Weak Secret Key Attack (HS256 Only)
This attack is applicable when the alg
is a symmetric algorithm like HS256
. It tests the strength of the secret key used by the server.
- Overview: Developers sometimes hardcode weak or easily guessable secret keys like “secret”, “password”, or “123456” for convenience or testing. An attacker can discover these keys using an offline brute-force attack.
- Attack Scenario:
- Obtain a valid token signed with
HS256
. - Use a cracking tool like
hashcat
with a large wordlist to discover the secret key.
- Obtain a valid token signed with
- Key Command:
1 2
# Cracking a JWT secret key with Hashcat (Mode 16500) hashcat -m 16500 -a 0 <jwt_token_here> <wordlist_file_path>
- Testing Method: Attempt to crack the secret key using
hashcat
orJohn the Ripper
. A successful attempt yields the master key, allowing the attacker to forge any valid token at will.
4. Header Parameter Injection: jku
and kid
jku
(JWK Set URL) Injection:- Overview: The
jku
header specifies a URL pointing to a set of keys (in JWK format) to be used for signature verification. If the server trusts this URL without proper validation, an attacker can supply their own malicious URL. - Attack Scenario: The attacker creates a token signed with their own key pair and hosts the corresponding public key on their server. They then change the
jku
header value to their server’s URL and send the token. The server will fetch the public key from the attacker’s server, use it to verify the signature, and trust the token as valid.
- Overview: The
kid
(Key ID) Injection:- Overview: The
kid
header is used to specify which of several keys to use for verification. If thekid
value is processed in an unsafe way, such as being used to construct a file path, it can be vulnerable to Path Traversal. - Attack Scenario: The attacker injects a payload like
../../../../dev/null
into thekid
value. If the server attempts to use this path to read a key file, it may end up using a null or predictable value as the key, thereby neutralizing the signature verification logic.
- Overview: The
Remediation and Mitigation Strategies
JWT vulnerabilities almost always stem from inadequate server-side validation logic. The following are key defensive strategies for a secure JWT implementation.
Use a Trusted and Up-to-Date Library: Do not implement security yourself. Use a well-vetted and actively maintained JWT library for your programming language. Older libraries are more likely to be vulnerable to known attacks like
alg:none
.Enforce an Algorithm Allowlist: Never trust the
alg
header from a client-supplied token. Your server should explicitly define an allowlist of accepted algorithms (e.g.,['RS256', 'ES256']
). Any token with analg
value not on this list must be immediately rejected. This is the most effective defense against Algorithm Confusion attacks.- Establish a Strong Key Management Policy:
- For Symmetric Keys (HS256): Use a long, complex secret generated by a cryptographically secure random number generator. Never hardcode secrets in source code; use environment variables or a secure secrets management system like Vault or AWS KMS.
- For Asymmetric Keys (RS256, etc.): Store the private key in a highly secure location with strict access controls. It is recommended to serve the public key via a standard
/.well-known/jwks.json
endpoint.
- Strengthen Header Input Validation:
- If you must use the
jku
header, validate the provided URL against an allowlist of trusted domains. - When using the
kid
header, sanitize the input to ensure it conforms to an expected format (e.g., a UUID) and filter out special characters (like.
,/
,\
) to prevent Path Traversal.
- If you must use the
- Design a Secure Payload and Token Lifecycle:
- Short Expiration Times: Use the
exp
claim to set short token lifetimes (e.g., 15 minutes). - Exclude Sensitive Data: Do not store personally identifiable information (PII) or other sensitive data in the JWT payload.
- Implement Revocation: Implement a server-side revocation list or a similar mechanism to immediately invalidate tokens when a user logs out or changes their password.
- Short Expiration Times: Use the
JWT 핵심 취약점 분석 및 공격 시나리오
성공적인 JWT 공격의 대부분은 서버의 서명 검증 로직을 우회하는 데서 시작합니다. 서명만 무력화할 수 있다면, 공격자는 토큰의 내용을 원하는 대로 조작하여 서버를 기만할 수 있습니다.
1. 서명 검증 우회: alg:none
공격
가장 기본적이면서도 반드시 확인해야 하는 취약점입니다.
- 개요: 공격자는 JWT 헤더의
alg
(알고리즘) 클레임을none
으로 설정하고 서명 부분을 완전히 제거하여 토큰을 전송합니다. 서버 측 라이브러리가 이를 허용할 경우, 서명 검증 절차를 생략하고 페이로드의 내용을 그대로 신뢰하게 됩니다. - 공격 시나리오:
- 정상적인 토큰을 획득하여 구조를 분석합니다.
- 헤더의
alg
값을none
으로 변경합니다. - 기존 토큰의 세 번째 부분인 서명(Signature)을 제거합니다.
Header.Payload.
(마지막 점 포함) 형식으로 조작된 토큰을 서버에 전송합니다.
- 핵심 페이로드:
- 변조 전 헤더:
{"alg": "HS256", "typ": "JWT"}
- 변조 후 헤더:
{"alg": "none", "typ": "JWT"}
- 변조 전 헤더:
- 테스트 방법: Burp Suite의 JWT Editor나 Repeater 기능을 사용하여 헤더와 서명을 수동으로 조작하고 서버의 응답을 확인합니다. 200 OK 또는 정상 처리 응답이 오면 취약점이 존재합니다.
2. 알고리즘 혼동 공격: RS256에서 HS256으로
기술적으로 가장 흥미로우며 파급력이 큰 공격입니다. 비대칭키(RS256)를 사용해야 할 서버가 대칭키(HS256) 토큰을 처리하도록 속이는 방식입니다.
- 개요: RS256 서명 검증에 사용되는 공개키(Public Key)는 말 그대로 외부에 공개되어 있습니다. 공격자는 이 공개키를 HS256의 대칭 비밀키(Symmetric Secret Key)처럼 사용하여 토큰에 서명합니다. 서버가 알고리즘 유형을 제대로 강제하지 않으면, 공개키를 비밀키로 착각하여 조작된 서명을 유효한 것으로 처리합니다.
- 공격 시나리오:
alg
가RS256
으로 설정된 토큰을 식별합니다.- 서버의 공개키를 획득합니다. 보통
/.well-known/jwks.json
과 같은 공개 엔드포인트에서 찾을 수 있습니다. - 원하는 내용으로 페이로드를 조작합니다 (예:
role
을admin
으로 변경). - 헤더의
alg
값을RS256
에서HS256
으로 변경합니다. - 2단계에서 획득한 공개키를 비밀키로 사용하여, 조작된 헤더와 페이로드에 대한 HS256 서명을 생성합니다.
- 완성된 토큰을 서버로 전송합니다.
- 테스트 방법: 공개키를 획득한 후, CyberChef나 스크립트를 이용해 HS256 서명을 생성하고 토큰을 위조하여 테스트합니다.
3. 취약한 비밀 키 추측 공격 (HS256 한정)
alg
가 HS256
인 경우, 서버가 사용하는 비밀 키의 강도를 테스트합니다.
- 개요: 개발자가 테스트나 편의를 위해 “secret”, “password”, “123456” 등 추측하기 쉬운 비밀 키를 하드코딩하는 경우가 있습니다. 공격자는 이를 오프라인에서 무차별 대입 공격으로 찾아낼 수 있습니다.
- 공격 시나리오:
HS256
으로 서명된 유효한 토큰을 획득합니다.hashcat
과 같은 크래킹 도구와 대규모 단어 목록(Wordlist)을 사용하여 비밀 키를 찾아냅니다.
- 핵심 명령어:
1 2
# Hashcat을 이용한 JWT 비밀 키 크래킹 (Mode 16500) hashcat -m 16500 -a 0 <jwt_token_here> <wordlist_file_path>
- 테스트 방법:
hashcat
이나John the Ripper
를 사용하여 비밀 키 크래킹을 시도합니다. 성공하면 시스템의 모든 토큰을 위조할 수 있는 마스터키를 획득하게 됩니다.
4. 헤더 파라미터 인젝션: jku
와 kid
jku
(JWK Set URL) 인젝션:- 개요:
jku
헤더는 검증에 사용할 공개키(JWK)의 위치를 URL로 지정합니다. 서버가 이 URL을 아무런 검증 없이 신뢰한다면, 공격자는 자신의 악의적인 URL을jku
값으로 제공할 수 있습니다. - 공격 시나리오: 공격자는 자신의 키 페어로 서명한 토큰을 만들고, 해당 키의 공개키를 자신의 서버에 호스팅합니다. 그리고
jku
헤더 값을 자신의 서버 주소로 변경하여 토큰을 전송합니다. 서버는 공격자의 서버에서 공개키를 받아와 서명을 검증하고, 이를 유효한 토큰으로 신뢰하게 됩니다.
- 개요:
kid
(Key ID) 인젝션:- 개요:
kid
헤더는 서버가 여러 키를 관리할 때 특정 키를 식별하는 데 사용됩니다. 만약kid
값이 파일 시스템 경로와 같이 예측 가능한 방식으로 처리된다면, 경로 조작(Path Traversal) 공격에 취약할 수 있습니다. - 공격 시나리오: 공격자는
kid
값에../../../../dev/null
과 같은 페이로드를 주입합니다. 서버가 해당 경로의 파일을 키로 사용하려 할 때, 비어있거나 예측 가능한 값을 키로 사용하게 되어 서명 검증 로직이 무력화될 수 있습니다.
- 개요:
대응 및 완화 방안 (Remediation and Mitigation)
JWT 관련 취약점은 대부분 서버 측의 검증 로직 미흡으로 인해 발생합니다. 다음은 안전한 JWT 구현을 위한 핵심적인 방어 전략입니다.
신뢰할 수 있는 최신 라이브러리 사용: 보안은 직접 구현하는 것이 아닙니다. 커뮤니티에서 검증되고 활발히 유지보수되는 최신 버전의 JWT 라이브러리를 사용하십시오. 오래된 라이브러리는
alg:none
과 같은 알려진 취약점에 노출되어 있을 가능성이 높습니다.알고리즘 화이트리스트 적용: JWT 검증 시, 토큰 헤더의
alg
값을 절대로 신뢰해서는 안 됩니다. 서버에서 허용할 알고리즘 목록(예:['RS256', 'ES256']
)을 명시적으로 지정하고, 이 목록에 포함되지 않은alg
값으로 들어온 토큰은 즉시 거부해야 합니다. 이는 알고리즘 혼동 공격을 막는 가장 효과적인 방법입니다.- 강력한 키 관리 정책 수립:
- 대칭키(HS256) 사용 시: 암호학적으로 안전한 난수 생성기를 통해 생성된, 충분히 길고 복잡한 문자열을 비밀 키로 사용해야 합니다. 소스 코드에 비밀 키를 하드코딩하지 말고, 환경 변수나 Vault, AWS KMS와 같은 안전한 보안 저장소를 통해 관리하십시오.
- 비대칭키(RS256 등) 사용 시: Private Key는 누구도 접근할 수 없는 안전한 위치에 보관해야 하며, Public Key는 표준에 따라
/.well-known/jwks.json
엔드포인트를 통해 배포하는 것을 권장합니다.
- 헤더 입력 값 검증:
jku
헤더를 사용해야 한다면, URL이 신뢰할 수 있는 특정 도메인에 속하는지 화이트리스트 기반으로 검증해야 합니다.kid
헤더 값을 사용할 때는, 예상되는 형식(예: UUID)인지 확인하고 파일 경로에 사용될 수 있는 특수문자(.
,/
,\
)를 필터링하여 경로 조작 공격을 원천적으로 차단해야 합니다.
- 페이로드 설계 및 토큰 생명주기 관리:
- 짧은 만료 시간:
exp
클레임을 사용하여 토큰의 유효 기간을 가능한 짧게(예: 15분) 설정하십시오. - 민감 정보 배제: 페이로드에는 개인 식별 정보(PII)나 내부 시스템 정보 등 민감한 데이터를 포함하지 마십시오.
- 로그아웃 및 폐기: 사용자가 로그아웃하거나 비밀번호를 변경할 경우, 해당 토큰을 즉시 무효화할 수 있는 폐기 목록(Revocation List) 또는 유사한 메커니즘을 서버 측에 구현해야 합니다.
- 짧은 만료 시간: