펜리젠트 헤더

JSON 웹 서명 디코딩: 검증 함정, 키 혼동 및 실제 익스플로잇

JSON 웹 서명(JWS) 디코딩은 서명된 데이터를 추출하고 무결성을 확인하기 위해 JWS 토큰 헤더, 페이로드, 서명 등의 구성 요소를 파싱하고 검증하는 프로세스입니다. 보안 및 모의 침투 테스트 상황에서 분석가는 JWS를 디코딩하면 어떤 클레임이 포함되어 있는지 이해하고, 잘못된 구성을 감지하고, 서명 우회 또는 토큰 위조와 같은 취약점을 초래할 수 있는 취약한 서명 관행을 식별하는 데 도움이 됩니다.

이 문서에서는 다음과 같이 설명합니다. JWS 디코딩이 중요한 이유에서 실제 코드를 사용하여 서명을 해독하고 확인하는 방법, 일반적인 함정, 보안 영향 및 2025년에 알아야 할 방어 전략에 대해 알아보세요.

JSON 웹 서명(JWS)이란 무엇인가요?

JSON 웹 서명(JWS) 는 서명된 메시지를 표현하는 간결하고 URL에 안전한 수단입니다. 이는 RFC 7515 를 통해 전송되는 데이터의 신뢰성과 무결성을 보장하기 위해 일반적으로 사용되며, REST API, 싱글사인온(SSO) 및 마이크로서비스 인증 플로우를 통해 전송되는 데이터의 신뢰성과 무결성을 보장합니다.

일반적인 JWS 토큰의 모습은 다음과 같습니다:

nginx

eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9. eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvZSJ9 . MEUCIQDh...

각 세그먼트는 다음과 같습니다. Base64URL 인코딩됩니다:

  1. 헤더 - 알고리즘과 토큰 유형에 대해 설명합니다.
  2. 페이로드(클레임) - 서명된 데이터
  3. 서명 - 무결성 증명

서명을 확인하지 않고 JWS를 디코딩하면 클레임이 드러나지만, 서명을 확인해야만 신뢰할 수 있는 출처에서 온 것임을 증명할 수 있습니다.

권위 있는 표준: RFC 7515 - https://tools.ietf.org/html/rfc7515

JSON 웹 서명 디코딩: 검증의 함정, 키 혼동, 실제 악용 사례 소개

왜 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크로스 플랫폼 CLIhttps://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없음 명시적으로 안전하지 않은 경우
  • 알고리즘 화이트리스트 적용
JSON 웹 서명 디코딩 펜리전트

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

기간의미
JWSJSON 웹 서명(서명만 가능)
JWEJSON 웹 암호화(암호화)

JWE는 기밀을 보호하고 JWS는 무결성과 신뢰성을 보호합니다. 많은 시스템에서 두 가지를 함께 사용합니다.

도구 및 라이브러리(2025 보안 스택)

  • Node.js jose - JWT/JWS 디코딩 및 확인
  • Python python-jose - 유연한 암호화 지원
  • OpenSSL - 낮은 수준의 암호화 인증
  • jwt.io - 빠른 웹 디코더
게시물을 공유하세요:
관련 게시물