JWT 도구
{
"alg": "HS256",
"typ": "JWT"
}{
"sub": "1234567890",
"name": "John Doe",
"admin": true,
"iat": 1516239022
}sub· 주체1234567890name· NameJohn Doeadmin· Admintrueiat· 발급 시간1516239022→ 2018. 01. 18. 09:30:22algHS256HMAC(대칭)typ· TypeJWT온라인 JWT 도구. JWT Token 디코딩, 검증 및 생성 지원. Header, Payload 및 서명 정보 확인. 인터페이스 인증 디버깅에 적합.
관련 추천
JWT HS256 서명용 HMAC-SHA256 Secret 생성·확인
JWT HS256 은 HMAC 과 Base64URL 의 조합입니다. HMAC 을 먼저 이해하면 JWT 서명을 추적하기 쉽습니다
JWT 내부에서 쓰는 Base64URL 인코딩 이해하기
JWT 의 Header, Payload, Signature 는 모두 Base64URL 형식으로 처리됩니다
JWT 의 세 세그먼트를 Base64URL 디코딩하기
JWT 를 나눈 뒤 각 세그먼트를 디코딩하면 평문 내용을 읽을 수 있습니다
Payload 를 숨겨야 한다면 JWE 또는 AES 검토하기
JWT Payload 는 기본적으로 평문입니다. 민감한 Payload 에는 JWE / AES 같은 암호화가 필요합니다
HS256 의 기반이 되는 SHA-256 해시 이해하기
HS256 은 HMAC 과 SHA-256 의 조합이므로 SHA-256 의 성질을 알면 이해가 쉬워집니다
방금 만든 JWT 로 API 를 직접 호출하기
JWT 를 확인한 뒤 Authorization: Bearer 에 붙여 넣어 실제 API 응답을 테스트할 수 있습니다
정규식 테스터
JWT 도구란?
JWT(JSON Web Token)는 RFC 7519 로 정의된 공개 표준입니다. HTTP 요청, OIDC 플로우, 마이크로서비스 호출 사이에서 “이 사용자가 누구인지”, “어떤 권한을 가졌는지” 같은 Claims 를 전달하는 데 쓰입니다. 일반적인 JWT 는 Base64URL 로 인코딩된 Header, Payload, Signature 세 부분을 `.` 으로 이어 붙인 문자열입니다. Header 에는 알고리즘과 타입, Payload 에는 Claims, Signature 에는 Header.Payload 에 대한 키 기반 서명이 들어갑니다.
**JWT 는 암호화가 아닙니다.** 가장 자주 생기는 오해가 이 부분입니다. 기본 JWT Payload 는 평문이라 누구나 Base64URL 디코딩으로 내용을 읽을 수 있습니다. JWT 가 제공하는 것은 내용 숨김이 아니라 “중간에 바뀌지 않았는지”를 확인하는 기능입니다. 비유하면 읽을 수 없는 티켓이 아니라 위조 방지 도장이 찍힌 티켓에 가깝습니다.
JWT 는 용도에 따라 여러 서명 알고리즘을 나눠 씁니다. HMAC 계열(HS256/HS384/HS512)은 같은 Secret 으로 서명과 검증을 하므로 단일 서비스나 신뢰된 내부 클러스터에 단순하고 빠릅니다. RSA 계열(RS256/RS384/RS512)은 개인키로 서명하고 공개키로 검증해 OIDC 에서 흔히 쓰입니다. RSA-PSS 계열(PS256/PS384/PS512)은 더 새로운 패딩을 쓰며, ECDSA 계열은 서명이 짧고, EdDSA(주로 Ed25519)는 빠르고 결정적인 서명이 특징입니다.
운영 환경에서 JWT 를 안전하게 쓰려면 기본 원칙을 지켜야 합니다. 비밀번호, 주민등록번호, 카드번호, API 키 같은 민감정보를 Payload 에 넣지 마세요. 서버는 Token Header 의 `alg` 를 믿지 말고 허용 알고리즘을 고정해야 합니다. HMAC Secret 은 짧은 문자열이 아니라 충분히 랜덤한 값이어야 하며, 서명뿐 아니라 `exp`, `nbf`, `iss`, `aud` 도 함께 검증해야 합니다. 이 도구는 Claims 상태를 강조해 서명 문제인지, 시간 또는 Claims 문제인지 빨리 구분하도록 돕습니다.
JWT 는 세션을 완전히 대체하는 기술이 아닙니다. 세션은 상태를 서버의 Redis 나 DB 에 두고, JWT 는 상태를 Token 안에 담습니다. 마이크로서비스, Stateless API, 모바일 앱, CORS 가 많은 구조에서는 JWT 가 편리하지만 즉시 강제 로그아웃이나 즉시 폐기가 중요한 업무 시스템에서는 세션이 더 다루기 쉬울 수 있습니다. 이 도구는 JWT 파싱, 서명 검증, Payload 편집, 재서명을 한 번에 확인하는 작업대입니다.
사용 사례
- JWT 온라인 디코딩: OAuth 2.0 / OIDC 로그인 디버깅 중 Header 알고리즘과 Payload Claims 를 빠르게 확인합니다
- JWT 서명 검증: Secret 또는 공개키로 서명을 검증해 401 원인이 서명 불일치, 만료, 알고리즘 불일치 중 무엇인지 가려냅니다
- 연동 테스트용 JWT 생성: 백엔드에 임시 발급 코드를 부탁하지 않고 브라우저에서 테스트 키 페어로 JWT 를 발급합니다
- PEM ↔ JWK 변환: OIDC IdP 가 JWK 를 제공했지만 서버는 PEM 을 요구하는 상황에서 OpenSSL 스크립트 없이 형식을 맞춰 봅니다
- 401 Unauthorized 진단: 만료 시간, alg 와 Gateway 설정, 키 일치 여부, PEM 형식을 순서대로 확인합니다
- RS256 과 PS256 비교: 같은 RSA 키 페어로 알고리즘을 바꿔 OIDC Provider, AWS SigV4 와의 차이를 확인합니다
- JWT 내부 구조 학습: alg 를 바꾸거나 Payload 를 수정하거나 키를 교체했을 때 서명이 어떻게 깨지는지 바로 확인합니다
이용 방법
- Token 붙여 넣기: JWT 문자열을 입력하면 Header, Payload, Signature 로 자동 분리되고 각각 JSON 으로 보기 좋게 정리됩니다
- 알고리즘 선택: HS256 / RS256 / ES256 / PS256 / EdDSA 등을 전환합니다. Header.alg 를 기준으로 추정하고 불일치가 있으면 표시합니다
- 키 가져오기: HMAC Secret, PEM 문자열, JWK JSON 을 붙여 넣습니다. 비대칭 알고리즘은 “키 페어 생성”으로 테스트 키를 바로 만들 수 있습니다
- 검증 또는 재서명: Decode 모드에서는 공개키로 서명을 검증하고, Encode 모드에서는 Claims 를 수정한 뒤 개인키로 서명해 새 Token 을 만듭니다
Output Example
A real MP3 file encoded to a Data URI — copy-ready:
Header (Base64URL): eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
Payload(Base64URL): eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkphbmUgRG9lIiwiaWF0IjoxNzE2MjM5MDIyfQ
Signature: kZJfaYjK3iCkVFL5EL9zGRZ5SmD8_x2h6B5c7pVFfVGo
Header 디코딩:
{
"alg": "HS256",
"typ": "JWT"
}
Payload 디코딩:
{
"sub": "1234567890",
"name": "Jane Doe",
"iat": 1716239022 // 2024-05-20 14:23:42 UTC
}주요 기능
- 디코딩·검증·생성을 한 화면에서 처리: Token 을 붙여 넣으면 Header/Payload/Signature 로 나누고, 알고리즘과 키를 바꿔 서명을 검증한 뒤 Claims 를 수정해 다시 서명할 수 있습니다
- 13가지 알고리즘 지원: HS256/HS384/HS512, RS256/RS384/RS512, ES256/ES384/ES512, PS256/PS384/PS512, EdDSA 를 다루며 OAuth 2.0, OIDC, JWS, API Gateway, SSO 디버깅에 맞습니다
- PEM 과 JWK 형식 지원: RSA, ECDSA, Ed25519 키를 PEM 문자열 또는 JWK JSON 으로 읽을 수 있고, OIDC 의 `/.well-known/jwks.json` 출력도 그대로 확인할 수 있습니다
- HMAC Secret 입력 형식 선택: UTF-8 문자열, Hex 바이트, Base64/Base64URL Secret 을 전환할 수 있어 “겉보기엔 같은데 서명이 안 맞는” 문제를 빠르게 좁힐 수 있습니다
- 브라우저에서 테스트용 키 페어 생성: RSA-2048, RSA-4096, P-256, P-384, Ed25519 키 페어를 만들고 PEM/JWK 두 형식으로 바로 확인합니다
- Claims 의미 기반 표시: exp / iat / nbf 를 사람이 읽는 시간으로 바꾸고, 만료됨·아직 유효하지 않음·발급 시각 상태를 눈에 띄게 표시합니다. Header 의 alg / typ / kid 도 따로 확인할 수 있습니다
- 100% 클라이언트 처리: 파싱, 검증, 서명은 브라우저의 Web Crypto API 로 실행되며 Token, 키, Payload 는 브라우저 밖으로 나가지 않습니다
- 원클릭 복사: Header, Payload, Signature, 새로 만든 Token 을 각각 복사해 문서, 이슈, curl 명령에 바로 붙여 넣을 수 있습니다
코드 예제
50 lines of Node.js: hand-written HS256 sign and verify
javascriptDistills JWT's core mechanism: encode Header and Payload in Base64URL, then HMAC-SHA256 the `header.payload` string. In production, use a library like jsonwebtoken or jose — this snippet exists to make signature failures debuggable.
const crypto = require('node:crypto')
function b64url(input) {
return Buffer.from(input)
.toString('base64')
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '')
}
function hmacSign(data, secret) {
return b64url(crypto.createHmac('sha256', secret).update(data).digest())
}
function sign(payload, secret) {
const header = b64url(JSON.stringify({ alg: 'HS256', typ: 'JWT' }))
const body = b64url(JSON.stringify(payload))
const signature = hmacSign(`${header}.${body}`, secret)
return `${header}.${body}.${signature}`
}
function verify(token, secret) {
const [h, p, s] = token.split('.')
const expected = hmacSign(`${h}.${p}`, secret)
const a = Buffer.from(s)
const b = Buffer.from(expected)
return a.length === b.length && crypto.timingSafeEqual(a, b)
}
const SECRET = 'my-super-secret-key'
const payload = { userId: 42, role: 'admin', exp: Math.floor(Date.now() / 1000) + 3600 }
const token = sign(payload, SECRET)
console.log(token)
console.log(verify(token, SECRET)) // true
console.log(verify(token, 'wrong-key')) // falseBrowser-side: Web Crypto API for HMAC signing
htmlThe core idea of this tool's front-end: use the browser's native crypto.subtle for HMAC, RSA, ECDSA, RSA-PSS and Ed25519 verification — no third-party library needed. Drop this into any HTML page to mint HS256 tokens.
<!doctype html>
<html>
<body>
<pre id="out"></pre>
<script>
const out = document.getElementById('out')
const b64url = buf =>
btoa(String.fromCharCode(...new Uint8Array(buf)))
.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '')
const b64urlStr = str => b64url(new TextEncoder().encode(str))
async function sign(payload, secret) {
const header = b64urlStr(JSON.stringify({ alg: 'HS256', typ: 'JWT' }))
const body = b64urlStr(JSON.stringify(payload))
const data = new TextEncoder().encode(`${header}.${body}`)
const key = await crypto.subtle.importKey(
'raw',
new TextEncoder().encode(secret),
{ name: 'HMAC', hash: 'SHA-256' },
false,
['sign']
)
const sig = await crypto.subtle.sign('HMAC', key, data)
return `${header}.${body}.${b64url(sig)}`
}
;(async () => {
const token = await sign({ user: 'alice', role: 'admin' }, 'browser-demo-secret')
out.textContent = token
})()
</script>
</body>
</html>Node.js: verify RS256 with jose (the right way)
javascriptUse a mature library like jose, jsonwebtoken, or PyJWT in production — never roll your own. This snippet shows how jose verifies an RS256 token, prints the failure reason on error (alg mismatch, bad signature, expired, kid not found, etc).
import { jwtVerify, importSPKI } from 'jose'
import { readFile } from 'node:fs/promises'
const token = 'eyJhbGciOiJSUzI1NiIsImtpZCI6IjEifQ.payload.signature'
const publicKeyPem = await readFile('public.pem', 'utf8')
try {
const { payload, protectedHeader } = await jwtVerify(
token,
await importSPKI(publicKeyPem, 'RS256'),
{
issuer: 'https://idp.example.com',
audience: 'my-app',
algorithms: ['RS256'], // critical: algorithm whitelist blocks alg:none and HS256-substitution attacks
}
)
console.log('alg =', protectedHeader.alg)
console.log('sub =', payload.sub)
} catch (err) {
console.error('verify failed:', err.code, err.message)
// common: ERR_JWT_EXPIRED / ERR_JWS_INVALID / ERR_JWS_SIGNATURE_VERIFICATION_FAILED
}Python: parse a token and print its Claims with PyJWT
pythonThe most common way to debug JWT on the Python side. PyJWT's decode() validates exp / nbf / iat by default and returns the result as a plain dict.
import jwt
token = 'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0In0.SflKxw'
# Parse (no signature check, just look at Header and Payload)
print(jwt.get_unverified_header(token))
# {'alg': 'HS256', 'typ': 'JWT'}
print(jwt.decode(token, options={'verify_signature': False}))
# {'sub': '1234'}
# Full verification
claims = jwt.decode(
token,
'my-super-secret-key',
algorithms=['HS256'],
audience='my-app',
issuer='my-service',
)
print(claims['sub'])5가지 JWT 서명 알고리즘 비교: 어떤 걸 선택할까?
JWT는 단일 알고리즘이 아니라 5가지 알고리즘이 키·성능·보안·호환성에서 각자 트레이드오프를 가집니다. 먼저 시나리오를 보고 알고리즘을 고르면 많은 시행착오를 줄일 수 있습니다.
| 알고리즘 | 유형 | 키 | 성능 | 전형적 시나리오 | 주의점 |
|---|---|---|---|---|---|
HS256 | HMAC 대칭 | 동일 Secret | 매우 빠름 | 서비스 클러스터 내부, 신뢰 환경, 모놀리식 앱 | Secret은 검증 측에 누설 금지; 최소 32바이트 랜덤 |
RS256 | RSA 비대칭 | 개인키 서명 / 공개키 검증 | 중간 | OIDC, API 게이트웨이, 기업 SSO, 공개·개인키 분리 필요 | RSASSA-PKCS1-v1_5 사용, 언어 간 패딩 고정 필요 |
PS256 | RSA-PSS 비대칭 | 개인키 서명 / 공개키 검증 | 중간 | AWS SigV4, AWS Cognito, 새 OIDC IdP | saltLength 명시적 고정 필수 (OpenSSL/jose=32, Go=hash 길이) |
ES256 | ECDSA 비대칭 | 개인키 서명 / 공개키 검증 | 빠름 + 서명 짧음 | Apple Sign in with Apple, 모바일, 저대역폭 시나리오 | 서버와 곡선(P-256/P-384/P-521) 일치 필요 |
EdDSA | Ed25519/Ed448 | 개인키 서명 / 공개키 검증 | 매우 빠름(결정적 서명) | OAuth 2.1, 새 프로토콜, 고빈도 검증 | Web Crypto는 Ed25519 지원, Ed448는 전체 플랫폼 미지원 |
Best Practices
운영 환경의 Secret/개인키는 온라인 도구에 절대 붙여넣지 않기
본 도구는 100% 브라우저 로컬에서 처리되지만(Token과 키를 업로드하지 않음), 디버깅 습관이 자리 잡으면 운영 환경의 장기 Secret/개인키/Access Token을 잘못된 온라인 도구에 붙여넣거나 스크린샷으로 누설하기 쉽습니다. 장기 Token(Refresh Token, 운영 개인키, API Key)은 반드시 로컬 통제 환경에서 처리하세요. 본 도구는 단기 Access Token 디버깅, 연동 테스트 키 페어, JWT 구조 학습에만 사용하세요.
OWASP JSON Web Token Cheat Sheet서버는 알고리즘을 화이트리스트로 고정하고 Token Header.alg를 신뢰하지 말 것
alg: none 공격(CVE-2015-9235 등)과 HS256 치환 공격(공개키를 Secret으로 사용해 RSA 서버를 속임)은 서버가 Header가 선언한 알고리즘으로 검증 로직을 선택하는 데서 비롯됩니다. 운영 코드에서는 `algorithms: ['RS256']`처럼 화이트리스트를 하드코딩하고, Token이 알고리즘을 결정하도록 허용해서는 안 됩니다. 디버깅 중 Header.alg와 서버 기대치가 다르면 Token 내용보다 서버 설정을 먼저 의심하세요.
HS256 Secret은 최소 32바이트 랜덤 값 사용
HS256은 HMAC-SHA256을 사용하므로 키 길이가 다이제스트 길이(32바이트)보다 짧으면 무차별 대입 비용이 크게 낮아집니다. `'my-secret'`, `'password123'` 같은 짧은 문자열이나 업무명/회사명/연도 결합은 사용하지 마세요. 표준 방법: `openssl rand -base64 32` 또는 `crypto.randomBytes(32).toString('base64url')`로 생성해 환경 변수 / KMS / 키 관리 서비스에 저장하고, 코드에는 절대 쓰지 마세요.
JWT에 사용자 민감정보를 넣어도 안전한가요?운영 JWT는 서명뿐 아니라 exp/nbf/iat/iss/aud 모두 검증해야 함
서명 검증이 통과해도 "변조되지 않았다"는 증명일 뿐 "아직 유효하다", "이 IdP가 발급했다", "이 앱 대상으로 발급했다"는 증명이 아닙니다. 운영 환경에서는 exp(만료), nbf(발효 시각), iat(발급 시각), iss(발급자), aud(대상) 등 관련 Claim을 모두 강제 검증해야 합니다. OWASP도 이 4-5개 항목을 필수 검증 항목으로 명시합니다. 서명만 검증하고 시간을 검증하지 않는 것이 다수 Token 누설 사고(refresh token이 영원히 만료되지 않음)의 근본 원인입니다.
Token 만료 시간 계층화: Access 15-30분, Refresh 7-30일
Access Token은 API 호출용으로 만료 시간이 짧을수록 안전합니다(누설되어도 곧 무효화). Refresh Token은 Access Token 재발급용으로 길게 둘 수 있지만 서버 측에 저장하고 폐기 가능해야 합니다. 일반적인 경험치: Access 15-30분, Refresh 7-30일. Refresh Token Rotation(Refresh로 Access를 교환할 때마다 새 Refresh도 함께 발급하고 기존 Refresh를 즉시 무효화)을 함께 쓰면 누설 감지와 사용자 경험 사이의 균형을 잡을 수 있습니다.
무상태 vs 유상태 인증: JWT는 Session의 대체품이 아님
JWT는 상태를 Token 안에 담으므로 마이크로서비스의 수평 확장과 CORS 크로스 도메인에 자연스럽게 대응하지만, 폐기 비용이 높습니다(블랙리스트 또는 짧은 만료 필요). Session은 상태를 서버 측 Redis/DB에 저장해 "강제 로그아웃"이 가능하지만 공유 저장소가 필요합니다. **둘 중 하나가 아닙니다**: 단기 Access JWT + 서버 측 Refresh Token 세션 기록이 가장 흔한 하이브리드 방식으로, 무상태 확장과 즉시 폐기를 동시에 얻을 수 있습니다. 즉시 폐지가 필요한 금융/정부 핵심 시스템에서는 순수 JWT 사용을 신중히 고려하세요.
JWT에 사용자 민감정보를 넣어도 안전한가요?Payload는 기본 평문 가독, 민감 데이터는 JWT에 넣지 않기
JWT(JWS)는 기본적으로 Payload를 암호화하지 않으므로 Token을 가진 사람은 누구나 Base64URL로 디코딩해 내용을 볼 수 있습니다. **절대로** 비밀번호, 주민등록번호, 카드번호, API 키, Access Token, Refresh Token을 Payload에 넣지 마세요. JWT는 비민감 Claims(사용자 ID, 역할, 만료 시각, 테넌트 ID)에 적합하며, 민감 데이터는 서버가 sub로 재조회합니다. Payload 암호화가 필요하면 JWE(RFC 7516)를 사용하지만 성능이 2-5배 느리고 키 관리 복잡도가 늘어납니다. "비민감 Claim + 서버 측 조회" 패턴을 우선 고려하세요.
JWT란 무엇인가요?RSA-PSS(PS256/PS384/PS512) 언어 간 연동 시 saltLength 먼저 고정
RS256과 PS256은 상호 검증할 수 없습니다(패딩이 다름). PS256에는 또 하나의 함정이 있습니다: `saltLength` 파라미터입니다. OpenSSL 기본 32바이트, Node jose 기본 32바이트, Python PyJWT 기본은 hash 길이와 동일(SHA-256=32), Go 기본 `rsa.PSSSaltLengthEqualsHash`. 언어 간 연동 시 반드시 같은 값(권장 32바이트)으로 고정하세요. 고정하지 않으면 같은 RSA 키 페어로 서명한 PS256 Token이 다른 언어에서 검증에 실패합니다.
RS256과 PS256 언어 간 서명 검증 실패디버깅 흐름: 테스트 키 페어 사용, 운영은 건드리지 않기
연동 또는 로컬 개발 시에는 항상 새 테스트 키 페어를 생성하세요(HS256은 랜덤 Secret, RS256/ES256/EdDSA는 도구 원클릭 생성). 운영 IdP의 개인키나 회사 도메인의 Secret을 재사용하지 마세요. 디버깅이나 로컬 테스트가 끝나면 테스트 키를 즉시 폐기합니다. 본 도구의 "키 페어 생성" 기능이 바로 이를 위해 설계되었으며, RSA-2048/4096, P-256/P-384, Ed25519을 원클릭으로 생성해 연동이 끝나면 그대로 버릴 수 있습니다.
테스트용 JWT 생성 연동자주 묻는 질문
JWT 는 어떤 세 부분으로 구성되나요?
JWT 는 `Header.Payload.Signature` 형식입니다. 각 세그먼트는 Base64URL 로 인코딩됩니다. Header 는 알고리즘(예: HS256, RS256)과 typ 를 담고, Payload 는 sub, iat, exp, nbf, aud, iss 같은 Claims 를 담습니다. Signature 는 앞의 두 세그먼트에 대한 키 기반 서명이며, 내용 숨김이 아니라 변조 여부를 확인하기 위한 것입니다.
JWT 를 디코딩한 뒤 Payload 를 수정할 수 있나요?
볼 수도 있고 수정할 수도 있지만, 유효한 Token 을 마음대로 위조할 수는 없습니다. Header 나 Payload 를 한 글자라도 바꾸면 원래 Signature 는 무효가 되고 서버가 거부합니다. 수정한 Token 을 유효하게 만들려면 같은 알고리즘과 키로 다시 서명해야 합니다. 이 도구는 디코딩, 편집, 생성을 한 화면에서 처리해 테스트 Token 을 빠르게 만들 수 있게 합니다.
HS256, RS256, ES256, PS256, EdDSA 는 무엇이 다른가요?
HS256 은 HMAC + SHA-256 으로 같은 Secret 이 서명과 검증에 쓰이는 공통키 방식입니다. RS256 은 RSA 개인키로 서명하고 공개키로 검증하는 방식으로 OIDC 에서 흔합니다. PS256 은 RSA-PSS 를 쓰는 RS256 의 보안 개선 선택지입니다. ES256 은 P-256 타원곡선을 사용해 서명이 짧고, EdDSA(Ed25519)는 빠르고 결정적인 서명이 특징입니다.
JWT 가 계속 'Invalid Signature' 로 표시되는 이유는 무엇인가요?
가장 흔한 원인은 서버의 Secret 또는 공개키와 붙여 넣은 키가 다르거나, PEM 개행·빈 줄·끝 공백이 섞였거나, Base64 와 Base64URL 을 혼동했거나, Header 는 HS256 인데 RS256 으로 검증했거나, Secret 을 Hex/Base64 로 잘못 해석한 경우입니다. 먼저 키, 알고리즘, Secret 입력 형식을 고정하고 확인하세요.
같은 RSA 키로 RS256 과 PS256 을 서로 검증할 수 있나요?
**할 수 없습니다.** RS256 은 RSASSA-PKCS1-v1_5, PS256 은 RSA-PSS 로 패딩과 검증 로직이 다릅니다. 같은 RSA 키를 쓰더라도 RS256 으로 서명한 Token 은 PS256 으로 검증되지 않습니다. 서명 측과 검증 측의 알고리즘을 반드시 맞추고, RSA-PSS 에서는 saltLength 설정도 맞춰야 합니다.
alg: none 공격은 무엇이고 어떻게 막나요?
공격자가 Header 를 `{"alg":"none"}` 으로 바꾸고 서명 없는 Token 을 통과시키려는 고전적인 JWT 취약점입니다. RS256 을 HS256 으로 바꿔 공개키를 Secret 처럼 쓰게 하는 변형도 있습니다. 방어책은 분명합니다. 서버에서 `algorithms: ['RS256']` 처럼 허용 알고리즘을 고정하고, Token Header 가 검증 방식을 결정하게 두지 마세요.
PEM 과 JWK 는 어떻게 변환하나요? 어느 쪽이 더 흔한가요?
PEM 은 `-----BEGIN PUBLIC KEY-----` 로 감싼 Base64 문자열로 OpenSSL, Java, Go 같은 전통적인 서버 환경에서 흔합니다. JWK 는 `kty`, `n`, `e`, `kid`, `alg` 등을 담은 JSON 이며 OAuth 2.0 / OIDC 에서 표준적인 키 표현입니다. OIDC IdP 는 보통 `/.well-known/jwks.json` 으로 공개키를 JWK 로 제공합니다. 이 도구는 PEM 과 JWK 둘 다 읽을 수 있습니다.
브라우저만으로 JWT 서명을 검증할 수 있나요?
가능합니다. 브라우저 표준 Web Crypto API(`window.crypto.subtle`)는 HMAC, RSA, ECDSA, RSA-PSS, Ed25519 서명과 검증을 지원합니다. 이 도구는 프런트엔드에서 `crypto.subtle.importKey` 와 `crypto.subtle.verify` 를 사용하므로 Token 이나 키를 업로드하지 않고 검증할 수 있습니다. Web Crypto 는 HTTPS 또는 localhost 같은 안전한 컨텍스트에서 사용할 수 있습니다.
Token 이 서버로 전송되나요?
전송되지 않습니다. 파싱, 검증, 서명은 모두 브라우저 안의 Web Crypto API 로 실행됩니다. Token, Header, Payload, Signature, Secret, 개인키, 생성한 키 페어는 서버로 보내지지 않습니다. DevTools 의 Network 탭을 보면 Token 내용을 담은 외부 요청이 없는 것을 확인할 수 있습니다.
JWT 에 사용자 민감정보를 넣어도 안전한가요?
**안전하지 않습니다.** 일반 JWT Payload 는 평문이라 Token 을 가진 사람은 누구나 Base64URL 디코딩으로 내용을 읽을 수 있습니다. 비밀번호, 주민등록번호, 카드번호, API 키, access token, refresh token 등을 넣지 마세요. 비밀 유지가 필요하면 JWE 나 AES 같은 암호화 방식을 사용해야 합니다.
문제 해결
Invalid Signature: 서명이 유효하지 않음
Token 과 검증 키가 서로 맞지 않습니다. 흔한 원인은 서버 키와 붙여 넣은 키가 다르거나, 끝 공백·개행 같은 보이지 않는 문자가 섞였거나, Base64 와 Base64URL 을 혼동했거나, Header 는 HS256 인데 RS256 으로 검증하는 경우입니다. 먼저 키가 바이트 단위로 같은지 확인하세요. PEM 끝 개행, HMAC Secret 뒤 공백, JWK `k` 값의 잘못된 URL 디코딩을 확인합니다. 그다음 Header.alg 와 실제 선택한 알고리즘이 맞는지, Secret 입력 형식이 UTF-8 / Hex / Base64 중 무엇인지 고정해서 다시 검증합니다.
HTTP 401 Unauthorized: Token 만료 또는 iat 미래 시각
서명 검증은 통과했지만 `exp` 가 과거이거나, `nbf` 가 아직 미래이거나, `iat` 가 서버 현재 시각보다 미래일 수 있습니다. 로컬 환경, 컨테이너, CI 에서는 시계 차이도 자주 원인이 됩니다. `aud` 가 맞지 않아 다른 앱용 Token 을 현재 서버가 검증하는 경우도 있습니다. 이 도구의 Claims 강조 표시로 exp / nbf / iat 상태를 확인하세요. exp 가 빨간색이면 재발급, nbf 가 빨간색이면 유효 시작 시각, iat 가 미래라면 서버와 클라이언트의 시간 동기화를 점검합니다. aud 가 다르면 서버의 audience 설정을 확인합니다.
PEM 또는 JWK 가져오기 오류
PEM 에 불필요한 빈 줄이 있거나 `-----BEGIN PUBLIC KEY-----` 같은 헤더/푸터가 빠졌을 수 있습니다. JWK 에 `kty` / `n` / `e` / `kid` 같은 필수 필드가 없거나, JWK `k` 값이 Base64URL 형식이 아니거나, 개인키/공개키 종류를 잘못 넣은 경우도 있습니다. 표준 PKIX PEM 으로 다시 내보내거나 OIDC Discovery 의 `/.well-known/jwks.json` 출력 원본을 그대로 사용하세요. 복사 과정에서 개행, 따옴표, 이스케이프가 깨지지 않았는지도 확인합니다.
RS256 과 PS256 의 언어 간 서명 실패
RS256 은 RSASSA-PKCS1-v1_5, PS256 은 RSA-PSS 를 사용합니다. 같은 RSA 키라도 서로 교차 검증할 수 없습니다. RS256 으로 서명한 Token 은 PS256 검증에 실패하고 반대도 마찬가지입니다. 서명하는 쪽과 검증하는 쪽이 같은 알고리즘을 쓰는지 확인하세요. AWS SigV4 는 PS256, 많은 OIDC IdP 는 RS256 을 쓰는 경우가 많습니다. RSA-PSS 는 `saltLength` 설정도 중요하므로 Node, Go, OpenSSL 등의 구현 설정을 맞춰야 합니다.
alg: none 공격과 HS256 키 대체 공격
서버가 Token Header 의 alg 값만 보고 검증 방식을 정하면, 공격자가 `alg: none` 으로 바꿔 서명 없는 Token 을 통과시키거나 RS256 Token 을 HS256 으로 바꿔 공개키를 Secret 처럼 쓰게 만들 수 있습니다. 서버에서는 반드시 `algorithms: ['RS256']` 처럼 허용 알고리즘을 고정하고, Token 이 검증 방식을 정하게 두면 안 됩니다. 이 도구는 Header.alg 와 실제 선택한 알고리즘을 따로 보여 주고 불일치를 확인할 수 있게 합니다.
Privacy & Security
이 JWT 작업대는 브라우저 표준 Web Crypto API 를 사용해 100% 브라우저 안에서 동작합니다. 붙여 넣은 Token, Header, Payload, Signature, HMAC Secret, RSA/ECDSA 개인키, 생성한 키 페어, 모든 서명/검증 계산은 사용자의 기기 안에 머물며 서버로 전송되지 않습니다. 로그로 남기거나 분석하거나 캐시하지도 않습니다. 페이지가 한 번 로드된 뒤에는 오프라인에서도 사용할 수 있습니다. 다만 장기간 유효한 운영 Token 이나 운영 개인키를 아무 온라인 도구에 붙여 넣지 않는다는 기본 원칙은 지켜 주세요.
Supported Video Formats
| Format | MIME | Browser support | When to use |
|---|---|---|---|
| HS256 / HS384 / HS512 | HMAC + SHA-256/384/512 | Universal | 공통키 방식입니다. 같은 Secret 으로 서명과 검증을 하므로 단순하고 빠르지만, Secret 은 충분히 랜덤해야 하며 최소 32바이트 이상을 권장합니다. |
| RS256 / RS384 / RS512 | RSASSA-PKCS1-v1_5 + SHA-2 | Web Crypto API | 가장 흔한 비대칭 서명 방식입니다. 개인키로 서명하고 공개키로 검증합니다. 많은 OIDC IdP, API Gateway, 기업 SSO 에서 기본값으로 쓰입니다. |
| PS256 / PS384 / PS512 | RSA-PSS + SHA-2 | Web Crypto API | RS256 보다 새로운 RSA-PSS 기반 방식입니다. AWS SigV4, AWS Cognito, 최신 OIDC Provider 에서 쓰이는 경우가 있으며, saltLength 설정을 명시적으로 맞춰야 합니다. |
| ES256 / ES384 / ES512 | ECDSA + P-256/P-384/P-521 | Web Crypto API | 타원곡선 서명입니다. 서명이 짧아 JWT 전체 크기를 줄일 수 있고 성능도 좋습니다. Apple Sign in with Apple 에서는 ES256 이 기본적으로 쓰입니다. |
| EdDSA (Ed25519) | Ed25519 / Ed448 | Web Crypto API | 차세대 고성능 서명 알고리즘입니다. 같은 메시지와 같은 키는 항상 같은 서명을 만들며 nonce 재사용 위험이 없습니다. OAuth 2.1 이후의 새 설계에서도 선호되는 방향입니다. |
Authoritative References
- 텍스트 비교
- 바이너리 변환
- 시저 암호
- 모스 부호
- 16진수 변환
- 비디오를 Base64로 변환
- Base64를 동영상으로 변환
- 이미지를 Base64로 변환
- Base64 이미지 변환
- 텍스트를 Base64로 변환
- Base64 텍스트로 변환
- 파일 해시 검증
- File to Base64
- Base64 파일로 변환
- 오디오 → Base64
- Base64를 오디오로 변환
- AES 암호화 및 복호화
- DES 암호화/복호화
- Base32 인코더 디코더
- Base58 인코딩 및 디코딩
- Base64 인코딩
- Base64 디코드
- Base64 비교
- Base64 분할
- Base64 여러 줄 병합
- Base64 형식화
- Base64 형식 검사
- Base64 일괄 인코딩
- Base64 일괄 디코딩
- Base64 정리
- Base64 패딩 처리
- Base64 길이 통계
- Base64 16진수로 변환
- Base64 DataURL 변환
- Base64-Hex 양방향 변환
- Base85 인코딩/디코딩
- HMAC 생성 및 검증
- PBKDF2 키 파생
- MD5 해시값
- SHA-256 해시
- SHA1 해시
- SHA512 해시
- JWT 도구
- HTML 엔티티 인코딩/디코딩
- Unicode 이스케이프
- URL 인코딩
- URL Safe Base64
- MIME Base64
- Java 난독화
- JS 난독화
- PHP 난독화
- Python 난독화