Skip to content

test: JWT Redis JTI 공격 매트릭스 검증 자동화#144

Open
seonghooncho wants to merge 1 commit intodevelopfrom
feature/jwt-attack-matrix-validation-143
Open

test: JWT Redis JTI 공격 매트릭스 검증 자동화#144
seonghooncho wants to merge 1 commit intodevelopfrom
feature/jwt-attack-matrix-validation-143

Conversation

@seonghooncho
Copy link
Contributor

@seonghooncho seonghooncho commented Feb 26, 2026

근본 목적

현행 JWT/Redis JTI 회전 구조를 유지한 상태에서, 동시성/재사용/응답 유실/순서 역전 조건에서 탈취 감지 성능과 오감지 여부를 실측 데이터로 검증하고, 운영 관점에서 신뢰 가능한 결론을 도출한다.

비목적

토큰 구조 변경, Redis 키 구조 변경, 인증 정책 변경, 방어 로직 리팩터링은 본 PR 범위에 포함하지 않는다.

변경 요약

  • Docker 기반 로컬 검증 스택 추가
    • docker/security/docker-compose.jwt-matrix.yml
    • docker/security/env.jwt-matrix.example
  • 공격 매트릭스 정의 추가
    • scripts/security/jwt-attack-matrix.json
  • 자동 실행/집계 스크립트 추가
    • scripts/security/run-jwt-attack-matrix.sh
    • scripts/security/score-jwt-attack-matrix.sh
  • 목적 중심 검증 문서 추가
    • docs/security/jwt-jti-attack-matrix-validation.md

검증

  • 정적 검증
    • bash -n scripts/security/run-jwt-attack-matrix.sh
    • bash -n scripts/security/score-jwt-attack-matrix.sh
    • jq empty scripts/security/jwt-attack-matrix.json
    • .ai/scripts/verify-purpose-focus.sh docs --staged
    • .ai/scripts/verify-before-commit.sh
  • 실행 검증
    • 단일 드라이런: SCENARIOS=N1 ./scripts/security/run-jwt-attack-matrix.sh
    • 전체 매트릭스 1회: ./scripts/security/run-jwt-attack-matrix.sh
    • 결과 파일: /tmp/syncly-jwt-matrix/results-20260226T065752Z.ndjson (74 requests)
    • 집계 파일: /tmp/syncly-jwt-matrix/summary-20260226T065752Z.json

실험 수행 방식 (JWT)

이번 실험은 "가설이 실제 트래픽 형태에서 유지되는가"를 보기 위해, 단순 단건 API 확인이 아니라 요청 순서와 클라이언트 반영 상태까지 통제하는 방식으로 수행했다.

  1. 매 시나리오 시작 시 login으로 동일 조건의 refresh token을 발급받고, 해당 토큰의 sub/did/jti를 기준 축으로 삼았다.
  2. reissue 호출 직전/직후에 Redis 키(refresh:current:{userId}:{deviceId}, CASHED:UA_HASH:{userId}:{deviceId})를 읽어 상태 전이를 기록했다.
  3. 응답 유실 케이스는 서버 응답을 받은 뒤 클라이언트가 Set-Cookie를 적용하지 않는 방식으로 재현했다(drop).
  4. 동시성/순서 역전 케이스는 동일 refresh token으로 병렬 요청을 발사하고, 응답 적용 순서를 완료순/역완료순으로 나눠 측정했다.
  5. 공격 케이스는 UA 상이, UA 동일 spoof, UA 없음, 선점, 대량 병렬 재사용으로 분해해 어떤 조건에서 탐지/미탐이 생기는지 분리 관찰했다.

초기 테스트 목적과 검증 키 포인트

초기 목적은 다음 다섯 가지였다.

  1. 재사용 탐지: 이미 rotate된 refresh token이 다시 들어오면 탐지되는가.
  2. 동시성 안전성: 동일 token 동시 요청에서 Redis current가 일관되게 수렴하는가.
  3. 응답 유실 UX: 패킷 유실 상황에서 정상 사용자 재시도를 허용하는가.
  4. 경계조건 안정성: 응답 순서 역전에서 오탐/미탐이 생기는가.
  5. 정량 판단: 결과를 느낌이 아니라 TP/FN/FP/TN으로 평가 가능한가.

실험은 위 키 포인트를 각각 독립 시나리오(N1N5, A1A8)로 분리해 검증했다.

지표 정의와 의미

  • 요청 단위 분류
    • TP: 공격 요청을 탐지한 경우
    • FN: 공격 요청인데 탐지하지 못한 경우
    • FP: 정상 요청인데 탐지한 경우
    • TN: 정상 요청을 정상으로 통과시킨 경우
  • 인시던트 단위 분류
    • 동일 scenario에서 1회라도 탐지되면 해당 scenario를 탐지 성공으로 계산
  • 핵심 지표
    • detection_rate = TP / (TP + FN)
    • false_positive_rate = FP / (FP + TN)

요청 단위는 시스템이 "각 요청"을 얼마나 정확히 판단하는지 보여주고, 인시던트 단위는 운영자가 체감하는 "한 사건" 단위 방어 성공률을 보여준다.

결과 상세 해석 (서술)

전체 74개 요청에서 request level은 TP=56, FN=9, FP=1, TN=8이었고, detection rate는 0.8615, false positive rate는 0.1111이었다.

이 수치는 현재 구현이 공격 재사용을 상당수 잡아내지만, 특정 경계조건에서 미탐과 오탐이 분명히 존재함을 의미한다.

  • 공격 탐지가 잘 된 구간
    • A1/A3/A4/A5/A6/A8에서 공격 재사용이 JWT401_06 + current key 삭제로 귀결됐다.
    • A7(50 병렬 재사용)는 51요청 중 50건 탐지로 나타나, 대량 재사용 상황에서 원자 교체 기반의 방어 수렴은 확인됐다.
  • 미탐이 발생한 구간
    • A2(동일 UA spoof)는 incident_detected=false였다.
    • 이는 uaHash 기반 예외 허용 창에서 공격 요청이 정상 재시도로 분류될 수 있음을 의미한다.
  • 오탐이 발생한 구간
    • N3(응답 유실 후 10초 초과 재시도)는 정상 사용자 시나리오인데 탐지로 집계됐다.
    • 이는 UX 보완 로직의 허용 시간 밖 재시도는 정상이라도 탈취 재사용과 동일하게 해석된다는 의미다.

incident level에서는 TP=7, FN=1, FP=1, TN=4, detection rate 0.875, false positive rate 0.2였다.

즉 공격 시나리오 8개 중 7개는 최소 1회 이상 탐지했지만, 1개(A2)는 끝까지 놓쳤고, 정상 시나리오 5개 중 1개(N3)는 사건 단위 오탐으로 집계됐다.

엔지니어링 결론 (JWT)

이 실험 결과를 이슈 목적(탈취 감지/무효화 검증)에 대입하면, "원자적 JTI 비교/교체가 재사용 공격을 다수 조건에서 유의미하게 억제한다"는 가설은 검증되었다.

반면 "탈취 감지율 100%, 오감지 0건"은 현재 데이터로는 성립하지 않는다. 따라서 포트폴리오 문구는 수치와 한계를 함께 제시하는 형태로 작성해야 기술적으로 정직하다.

현행 uaHash 방식 한계 명시

  • 동일 UA 문자열을 재현한 공격 요청은 정상 재시도로 분류될 가능성이 있다(A2).
  • 응답 유실 보완 창(10초)을 넘는 정상 재시도는 공격 재사용과 동일 분류될 수 있다(N3).
  • 동시 재발급 + 응답 순서 역전 조건에서는 클라이언트 최종 쿠키와 Redis current가 불일치할 가능성을 항상 관찰 대상으로 유지해야 한다.

관련 이슈

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant