JWT 암호공학 실습 랩: 클레임 변조, 서명 검증 및 알고리즘 혼동 공격
Base64URL 단순 인코딩과 암호학적 서명의 차이를 명확히 이해하고 JWT 검증 라이브러리의 보안 취약점을 예방한다.
1. Production Scenario & Incident
운영 API가 Authorization 헤더로 JWT를 수신합니다. 공격자가 페이로드의 권한을 user에서 admin으로 변조하려 합니다. 이를 정확히 탐지하고 차단하세요.
2. Architectural Background & RFC Standards
RFC 7515 JWS 규격에 따라 서명은 비밀키를 사용해 계산됩니다. 페이로드의 한 글자만 바뀌어도 서버의 서명 검증 단계에서 즉시 탈락합니다.
- Compact Serialization: `Base64URL(Header) . Base64URL(Payload) . Base64URL(Signature)`
- Cryptographic Signature: For HS256, `HMACSHA256(HeaderB64 + "." + PayloadB64, secret)`. Modifying any character in the header or payload invalidates the signature.
- The "alg: none" Vulnerability: Unsanitized verification libraries historically allowed tokens specifying `"alg": "none"` to bypass signature verification entirely.
- Standard Registered Claims: `iss` (Issuer), `sub` (Subject), `aud` (Audience), `exp` (Expiration Time), `nbf` (Not Before), and `iat` (Issued At).
3. Hands-On Lab Instructions
Open the interactive JWT builder island below.
Inspect the default Header (`{"alg":"HS256","typ":"JWT"}`) and Payload (`{"sub":"user_42","role":"user"}`).
Modify `"role": "user"` to `"role": "admin"` in the payload editor. Notice how the middle Base64URL segment changes instantly while the signature remains calculated from the original.
Attempt to verify the tampered token against the server secret key in the verification console.
Implement strict backend verification code that locks the allowed algorithms to `["HS256"]` and enforces `exp` validation.
4. Interactive Lab Workbench
Edit headers, claims, and signing secrets live. Observe instant Base64URL encoding, HMAC-SHA256 signing, and signature verification failures.
Edit the payload to simulate tampering. Notice how the signature instantly updates!
5. Diagnostic Comprehension Questions
Are JSON Web Tokens (JWS compact format) encrypted by default?
Reveal Answer & Explanation →
✓ Correct Answer: No, standard JWS tokens are merely signed and Base64URL-encoded. Anyone can decode and inspect the payload claims in plaintext.
JWS (JSON Web Signature) provides integrity and authenticity, NOT confidentiality. The payload is encoded using Base64URL, which is trivially decodable by anyone. Confidential data must be encrypted using JWE (RFC 7516).
How should a secure backend verify incoming JWT signatures to prevent algorithm confusion attacks?
Reveal Answer & Explanation →
✓ Correct Answer: Explicitly restrict the verification function to a hardcoded whitelist of allowed algorithms (e.g., algorithms: ["HS256"]).
Never allow an unverified token header to dictate which algorithm the verification library uses. Explicitly pass allowed algorithms (such as `algorithms: ["HS256"]`) to prevent attackers from submitting "none" or asymmetric public keys disguised as symmetric HMAC secrets.
6. Progressive Diagnostic Hints
💡 Hint #1▼
💡 Hint #2▼
💡 Hint #3▼
7. Verified Production Solution
안전한 JWT 검증을 위해 백엔드 비밀키 일치 여부를 검사하고 none 알고리즘을 원천 차단해야 합니다.
// Production Node.js JWT Verification with jsonwebtoken
import jwt from 'jsonwebtoken';
const JWT_SECRET = process.env.JWT_SECRET_KEY; // High-entropy secret (>= 256 bits)
export function verifyUserToken(authHeader: string | undefined) {
if (!authHeader || !authHeader.startsWith('Bearer ')) {
throw new Error('Missing or malformed Authorization header');
}
const token = authHeader.slice(7);
// SECURE VERIFICATION:
// 1. Explicitly whitelist allowed algorithms (rejects "none" or RS256 confusion)
// 2. Enforces expiration (exp) and expected issuer (iss)
const decoded = jwt.verify(token, JWT_SECRET, {
algorithms: ['HS256'], // NEVER let the header dictate the algorithm!
issuer: 'https://auth.curious-techie.com',
audience: 'https://api.curious-techie.com',
clockTolerance: 5 // 5 seconds tolerance for clock skew
});
return decoded;
}- ✓1. Extract the token strictly from the `Authorization: Bearer <token>` header.
- ✓2. Explicitly specify `algorithms: ["HS256"]` in the verification call so the parser rejects tokens declaring `"alg": "none"` or mismatched asymmetric keys.
- ✓3. Validate standard claims: `exp` (reject expired tokens), `iss` (expected auth server), and `aud` (expected API audience).
- ✓4. Store the HMAC secret in a secure environment variable with at least 32 bytes (256 bits) of cryptographic entropy.
8. In-Depth Technical Explanation
"If an adversary modifies any bit of the JWT payload without the symmetric HMAC secret, the mathematical digest HMAC(Header + "." + Payload, Secret) will diverge from the transmitted signature; consequently, any compliant verification engine deterministically throws a JsonWebTokenError / SignatureVerificationFailed exception."
Underlying Root Cause Analysis
The cryptographic security of a JWT rests entirely on its third segment: the signature. In HMAC-SHA256, the server hashes the concatenated header and payload strings using a secret key only known to the server. If an adversary alters any claim in the payload, the resulting cryptographic hash changes completely (due to the avalanche effect). If the server verifies the signature before reading claims, the forgery is immediately rejected.
Production Engineering Best Practices
- →Use strong secrets with at least 256 bits of entropy generated from `/dev/urandom`.
- →Always set short token lifespans (5 to 15 minutes) combined with secure, HTTP-only refresh tokens.
- →Never store sensitive passwords, API keys, or personally identifiable information (PII) in JWT payloads.
Common Pitfalls to Avoid
- ✕Using `jwt.decode()` instead of `jwt.verify()`, which parses claims without checking the cryptographic signature.
- ✕Using weak, dictionary-word secret keys like "secret" or "password" that can be brute-forced offline in seconds.
- ✕Relying on JWT blacklist caches in relational databases, defeating the stateless advantage of tokens.
관련 기술 생태계 및 다음 학습 단계
관련 기술 아티클
JWT vs Session-Based Authentication: Architecture & Performance
Compare database session lookups with stateless JWT verification across scalability and revocation.
Troubleshooting: JWT Works in Postman but Fails in Browser
Diagnose and remediate CORS header stripping, HttpOnly cookie constraints, and preflight authorization failures.
관련 기술 질문
Can a JWT Be Decrypted by Anyone?
Answer: Yes, standard JSON Web Tokens (JWS) are signed, not encrypted. Anyone can decode and inspect the payload without the secret key.
Why Shouldn't You Store JWTs in LocalStorage?
Answer: Storing tokens in localStorage exposes them to instant exfiltration by any Cross-Site Scripting (XSS) vulnerability.
Can an Expired JWT Token Still Be Verified?
Answer: Yes, the cryptographic signature remains mathematically valid, but compliant libraries reject the token because exp is checked after signature verification.
개발자 표준 규격 및 레퍼런스
다음 학습 단계
JWT Interactive Tampering & Validation Lab
Put your theoretical understanding into practice by tampering with claims and testing signature rejection in the live sandbox.