JSON 웹 서명(JWS) 디코딩은 서명된 데이터를 추출하고 무결성을 확인하기 위해 JWS 토큰 헤더, 페이로드, 서명 등의 구성 요소를 파싱하고 검증하는 프로세스입니다. 보안 및 모의 침투 테스트 상황에서 분석가는 JWS를 디코딩하면 어떤 클레임이 포함되어 있는지 이해하고, 잘못된 구성을 감지하고, 서명 우회 또는 토큰 위조와 같은 취약점을 초래할 수 있는 취약한 서명 관행을 식별하는 데 도움이 됩니다.
이 문서에서는 다음과 같이 설명합니다. JWS 디코딩이 중요한 이유에서 실제 코드를 사용하여 서명을 해독하고 확인하는 방법, 일반적인 함정, 보안 영향 및 2025년에 알아야 할 방어 전략에 대해 알아보세요.
JSON 웹 서명(JWS)이란 무엇인가요?
JSON 웹 서명(JWS) 는 서명된 메시지를 표현하는 간결하고 URL에 안전한 수단입니다. 이는 RFC 7515 를 통해 전송되는 데이터의 신뢰성과 무결성을 보장하기 위해 일반적으로 사용되며, REST API, 싱글사인온(SSO) 및 마이크로서비스 인증 플로우를 통해 전송되는 데이터의 신뢰성과 무결성을 보장합니다.
일반적인 JWS 토큰의 모습은 다음과 같습니다:
nginx
eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9. eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvZSJ9 . MEUCIQDh...
각 세그먼트는 다음과 같습니다. Base64URL 인코딩됩니다:
- 헤더 - 알고리즘과 토큰 유형에 대해 설명합니다.
- 페이로드(클레임) - 서명된 데이터
- 서명 - 무결성 증명
서명을 확인하지 않고 JWS를 디코딩하면 클레임이 드러나지만, 서명을 확인해야만 신뢰할 수 있는 출처에서 온 것임을 증명할 수 있습니다.
권위 있는 표준: RFC 7515 - https://tools.ietf.org/html/rfc7515

왜 JWS를 디코딩해야 하나요? 보안 및 테스트 관점
JWS를 디코딩하는 데는 여러 가지 목적이 있습니다:
- 임베디드 클레임 이해하기: 사용자는 누구인가요? 권한이란 무엇인가요?
- 서명 알고리즘을 식별합니다: 약한 알고리즘(예,
없음또는HS256예측 가능한 키 포함) - 무결성을 평가합니다: 변조된 토큰 탐지
- 취약점을 발견하세요: 시그니처 우회, 알고리즘 다운그레이드 공격
공격적인 보안 관점에서 볼 때, 취약한 JWS 서명 관행을 발견하면 공격자가 토큰을 위조하고 권한을 상승시키는 익스플로잇으로 이어질 수 있습니다.
JWS 토큰의 해부학
일반적인 토큰에 대한 분석은 다음과 같습니다:
| 세그먼트 | 의미 | 예 |
|---|---|---|
| 헤더 | 알고리즘 및 메타데이터 | { "alg": "RS256", "typ": "JWT" } |
| 페이로드 | 클레임 | { "sub": "12345", "role": "admin" } |
| 서명 | 서명된 다이제스트 | 암호화된 헤더+페이로드의 Base64URL |
디코딩된 JWS는 헤더와 페이로드에 대한 일반 JSON을 표시합니다:
ini
HeaderJSON = base64url_decode(part1)PayloadJSON = base64url_decode(part2)
디코딩은 진위 여부를 증명하지 않으며 서명 확인만이 진위 여부를 증명합니다.
간단한 JWS 디코딩(인증 없이)
보안 분류에서 첫 번째 단계는 내부에 무엇이 있는지 확인하는 것입니다:
파이썬 예제(디코딩 전용)
python
import base64import json def base64url_decode(input_str): rem = len(input_str) % 4 input_str += "=" * (4 - rem)return base64.urlsafe_b64decode(input_str) token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMifQ.SflKxw..."header, payload, signature = token.split('.') header_json = json.loads(base64url_decode(header)) payload_json = json.loads(base64url_decode(payload)) print("Header:", header_json)print("Payload:", payload_json)
이렇게 하면 읽을 수 있는 JSON이 출력되지만 서명이 올바른지 여부는 검증하지 않습니다.
JWS 서명 확인(보안 중요)
토큰이 합법적인지 확인하려면 예상되는 알고리즘과 키를 사용하여 서명을 확인해야 합니다. 방법은 다음과 같습니다:
자바스크립트(Node.js) 사용 예시 jose
자바스크립트
import { jwtVerify } from "jose"; const token = "eyJ..."; const publicKey = /* 적절한 공개키, 예: JWKS 엔드포인트에서 로드 */; async function verifyToken() {try {const { payload } = await jwtVerify(token, publicKey);console.log("검증된 페이로드:", payload); } catch (e) {console.error("검증 실패:", e); } } verifyToken();
이렇게 하면 토큰이 공개 키에 해당하는 올바른 개인 키로 서명되었는지 확인할 수 있습니다.
실제 예제: OAuth 토큰 디코딩
많은 API가 액세스 제어를 위해 JWS 토큰을 발급합니다. 디코딩을 통해 사용자 및 세션 정보를 확인할 수 있습니다:
json
{ "iss": "", "sub": "alice", "exp": 1700000000, "scope": "읽기 쓰기" }
보안팀은 디코딩된 토큰을 검토하여 감사 범위와 만료 시간을 검토합니다.
JWS 구현의 일반적인 취약점
알고리즘 다운그레이드
일부 라이브러리에서는 변경을 잘못 허용합니다. alg 에 없음를 사용하여 공격자가 인증을 우회할 수 있도록 합니다.
안전하지 않은 헤더 예시:
json
{"alg":"none","typ":"JWT"}
공격 방어: 항상 다음과 같은 토큰은 거부합니다. 알고리즘: 없음 문맥상 명백히 안전하지 않은 경우.
약한 대칭 키(HS256)
공격자는 약하거나 예측 가능한 대칭 키를 사용하여 키를 추측하고 토큰을 위조할 수 있습니다.
완화:
- 강력한 비밀 키 사용(256비트 이상)
- 비대칭 알고리즘 선호(
RS256,ES256)
빠른 JWS 디코딩을 위한 CLI 도구
| 도구 | 설명 | 공식 |
|---|---|---|
| jwt.io 디버거 | 웹 기반 디코딩 및 확인 | https://jwt.io |
| jose CLI | 노드 기반 디코딩/검증 | https://github.com/panva/jose |
| jwt-cli | 크로스 플랫폼 CLI | https://github.com/mike-engel/jwt-cli |
CLI 디코딩 예시:
bash
jwt decode eyJhbGciOi...
취약점 시나리오: 토큰 위조(개념 증명)
서버가 잘못 수락한 경우 알고리즘: 없음공격자가 위조할 수 있습니다:
css
헤더: {"alg":"none","typ":"JWT"} 페이로드 {"sub":"attacker","role":"admin"} 서명: ""
개념 증명 스크립트(Python):
python
import base64import json def b64url(x): return base64.urlsafe_b64encode(x).rstrip(b'=').decode() header = {"alg":"none","typ":"JWT"} payload = {"sub":"공격자","role":"관리자"} token = f"{b64url(json.dumps(header).encode())}.{b64url(json.dumps(payload).encode())}."print("Forged token:", token)
방어:
- 다음과 같은 경우 토큰을 거부합니다.
alg는없음명시적으로 안전하지 않은 경우 - 알고리즘 화이트리스트 적용

2025년에 서명 인증이 중요한 이유
최신 마이크로서비스와 분산형 API에서 토큰은 액세스 결정을 주도합니다. 부적절한 인증은 다음과 같은 결과를 초래할 수 있습니다:
- 권한 에스컬레이션
- 무단 액세스
- 세션 하이재킹
모의 침투 테스터와 방어자는 프로그래밍 방식으로 대규모로 토큰을 해독하고 유효성을 검사할 수 있어야 합니다.
API에서 깨진 인증 감지하기
자동화된 스캐너는 API가 잘못된 JWS 서명을 수락하려고 시도하는지 확인할 수 있습니다.
파이썬 의사 코드(보안 검사)
python
def test_broken_verification(api_url, forged_token): headers = {"Authorization": f"Bearer {forged_token}"} response = requests.get(api_url, headers=headers)return response.status_code bad_api = test_broken_verification("", forged_token)if bad_api == 200:print("JWS 위조에 취약할 가능성이 있습니다")를 실행합니다.
API가 다음과 같이 응답하는 경우 200 OK토큰 수락 로직에 결함이 있을 수 있습니다.
방어 모범 사례
| 방어 | 설명 |
|---|---|
| 비대칭 키 사용 | 대칭 키보다 RS256, ES256 선호 |
| 알고리즘 화이트리스트 적용 | 예기치 않은 알고리즘 값 거부 |
| 짧은 토큰 수명 | 리플레이 위험 최소화 |
| 키 회전 | 서명 키를 정기적으로 업데이트 |
| 토큰 라이브러리 감사 | 종속성을 최신 상태로 유지 |
CI/CD 보안에 토큰 디코딩 통합
2025년에는 보안 파이프라인이 JWS 관행을 자동으로 검증하는 경우가 많습니다:
- JWT 구성의 자동 보푸라기 제거
- 안전하지 않은 라이브러리를 거부하는 CI 테스트
- 잘못된 토큰 수락에 대한 런타임 모니터링
CI 스크립트 스니펫 예시(Bash):
bash
1TP5코드에 "alg: none"을 사용하는 경우 거부"grep -R '"alg": *"none"' ./src && 종료 1
관련 개념: JWE 대 JWS
| 기간 | 의미 |
|---|---|
| JWS | JSON 웹 서명(서명만 가능) |
| JWE | JSON 웹 암호화(암호화) |
JWE는 기밀을 보호하고 JWS는 무결성과 신뢰성을 보호합니다. 많은 시스템에서 두 가지를 함께 사용합니다.
도구 및 라이브러리(2025 보안 스택)
- Node.js
jose- JWT/JWS 디코딩 및 확인 - Python
python-jose- 유연한 암호화 지원 - OpenSSL - 낮은 수준의 암호화 인증
- jwt.io - 빠른 웹 디코더

