본문 바로가기
Hack/Web

Secrets That Survive Everything: Runtime Credential Exposure in Production Web Applications

by Becoming a Hacker 2026. 9. 23.
반응형

  • 저자: Hemanth Gorijala
  • 발표: IEEE Access, 2026년 / arXiv v1, 2026-09-19
  • 원문: arXiv · DOI
  • Tags: Runtime Credential Exposure, Client-Side Secrets, Azure AD, APIM, JavaScript Bundle, Secret Scanning, OAuth, CryptoJS, DevSecOps, Web Security

본 글은 원 논문의 주요 기술적 내용을 이해하기 쉽게 요약·정리한 글입니다. 자세한 내용은 상단의 원문 링크를 참고하세요.

한눈에 보기

이 연구는 저장소가 아니라 실제 운영 웹 애플리케이션의 브라우저 응답을 검사해, 빌드 이후에만 나타나는 자격증명 노출을 측정합니다. 한 조직이 허가한 약 2,000개 자산 중 113개 애플리케이션에서 살아 있는 자격증명을 발견했고, 두 사례에서는 비인증 외부 사용자가 OAuth 토큰을 발급받아 백엔드 API의 사용자 정보에 접근할 수 있음을 통제된 범위에서 확인했습니다.

핵심 메시지는 단순합니다. 저장소·CI 단계 스캐닝이 통과되더라도 번들링, 런타임 구성 주입, 제3자 스크립트, 잘못된 억제 규칙 때문에 비밀이 최종 브라우저 아티팩트에 다시 나타날 수 있으므로, 배포 직전 산출물과 운영 응답을 별도로 검사해야 합니다.

연구 배경

SPA는 환경 변수와 구성 파일을 정적 JavaScript, JSON, HTML에 포함시킵니다. 공개 식별자인 client ID나 tenant ID 자체는 비밀이 아니지만, client secret·APIM subscription key·resource URI가 함께 노출되고 서비스 프린시펄 권한이 넓으면 인증 없는 방문자도 완전한 공격 체인을 구성할 수 있습니다.

기존 비밀 탐지기는 주로 저장소와 CI 로그를 봅니다. 이 논문은 사용자가 실제로 받는 HTTP 응답을 분석 단위로 삼고, 개별 문자열 탐지율뿐 아니라 서로 결합했을 때 토큰 발급과 API 호출이 가능한지까지 확인합니다.

공격 모델 / 전제 조건

공격자는 인터넷에서 웹 애플리케이션을 열 수 있는 비인증 사용자이며, HTTPS로 전달된 JavaScript·HTML·JSON·XML과 브라우저 네트워크 요청을 읽고 회수한 값으로 직접 요청을 보낼 수 있습니다. MITM, 서버 침해, 내부자 권한, 코드 삽입, 사회공학은 필요하지 않으며 서버 안에만 존재하는 비밀은 연구 범위에서 제외됩니다.

실제 피해에는 노출된 credential이 유효하고, tenant·resource·scope와 API 경로를 복원할 수 있으며, 서비스 프린시펄 또는 APIM 키에 민감한 권한이 있어야 합니다. CORS는 브라우저 스크립트의 교차 출처 호출을 제한할 뿐 서버 간 직접 요청을 막지 않으므로 보안 경계가 아닙니다.

비판적 검토 / 아쉬운 점

  1. 외적 타당성이 가장 큰 제약입니다. 한 조직의 Azure 중심 자산 약 2,000개를 조사했으므로 5.65%라는 비율을 일반 웹 전체에 적용할 수 없습니다. 여러 산업·클라우드의 무작위 표본과 조직별 클러스터 신뢰구간이 보완되어야 합니다.
  2. 도구 비교의 독립성이 충분하지 않습니다. 저자는 최고 성능 도구 SecretSifter의 개발자이고, Claude Opus 4.7이 후보 ground truth 생성에 참여했습니다. 공개 corpus에 대한 블라인드 제3자 라벨링과 교차 조직 재현이 있으면 이해충돌과 모델 보조 라벨 편향을 줄일 수 있습니다.
  3. 분모가 credential 단위에 치우칩니다. 같은 애플리케이션의 여러 값은 독립 표본이 아니며, 수동 발견 27건은 두 번째 LLM 교차검증에서 빠졌습니다. 애플리케이션 단위 민감도와 라벨러 간 원자료를 함께 공개해야 차이가 얼마나 견고한지 판단할 수 있습니다.
  4. 실제 악용 입증은 두 사례에 한정됩니다. 노출 113건 모두가 같은 수준의 계정 탈취나 데이터 접근으로 이어진 것은 아닙니다. 각 credential의 유효성·권한·회전 상태를 비파괴적으로 분류한 후속 실험이 필요합니다.

핵심 Root Cause

깨진 보안 불변조건은 “confidential client credential과 백엔드 접근 키는 서버 신뢰 경계를 넘어 브라우저가 받는 바이트에 포함되어서는 안 된다”입니다. 저장소 검사 완료 시점과 번들·배포·런타임 응답 생성 시점 사이에 보안 관찰 공백이 있고, 여기에 애플리케이션 권한 과다 부여가 결합해 공개 프런트엔드가 사실상 백엔드 credential 배포 채널이 됩니다.

CryptoJS로 구성값을 암호화해도 복호화 키와 코드가 같은 클라이언트에 있으면 비밀성이 생기지 않습니다. 문자열 은닉, Base64, minification은 보안 통제가 아니라 탐지 비용만 높이는 표현 변환입니다.

핵심 공격 원리

공격자는 번들과 런타임 구성에서 client ID, client secret, resource 또는 scope, APIM 키를 모으고 로그인 리다이렉트에서 tenant ID를 보충합니다. 그다음 OAuth client_credentials 흐름으로 애플리케이션 토큰을 발급받고, 번들 속 API 경로·JSON schema를 재구성해 Bearer 토큰과 Ocp-Apim-Subscription-Key를 함께 제시합니다.

두 번째 사례에서는 CryptoJS AES 암호문과 하드코딩된 키를 동일 클라이언트 코드에서 찾아 구성 전체를 복호화했습니다. 복호화 후의 credential로 토큰과 사용자 프로필 API 접근까지 확인했지만, 연구진은 파괴적 동작 전에 중단하고 공개 절차로 전환했습니다.

공격 흐름

  1. 대상 페이지와 동적 chunk, 구성 JSON/XML, 응답 헤더를 수집합니다.
  2. vendor-anchored 패턴, 키-값 문맥, Shannon entropy 3.5 bits/char 이상, PII 구조 검증으로 후보를 찾습니다.
  3. public identifier와 secret을 분리하고 tenant·resource·API 경로의 결합 관계를 복원합니다.
  4. 허가된 환경에서 credential 유효성과 OAuth 토큰 발급 여부를 최소 요청으로 확인합니다.
  5. 토큰·APIM 키가 동시에 필요한 API를 비파괴적으로 호출하고 노출 범위를 기록한 뒤 즉시 중단·신고합니다.

성공 조건 / 실패 조건

성공하려면 비밀값이 운영 응답에 포함되고 아직 회전되지 않았으며, 올바른 tenant·resource·scope를 찾을 수 있고, 발급된 토큰 또는 APIM 키가 민감 API 권한을 가져야 합니다. 완전한 Azure credential 세트가 없거나 secret이 폐기됐고, managed identity/BFF가 경계를 지키며, 최소 권한·audience 검증·추가 서버 측 인가가 적용되면 체인은 실패합니다.

탐지 관점에서는 비표준 변수명, 분할 문자열, 암호화 blob, 제3자 로더, source map 부재가 자동 도구를 실패시킬 수 있습니다. 반대로 단순 UUID·resource ID는 문맥 없이 비밀로 취급하면 오탐이 됩니다.

연구진의 실험 환경

연구진은 승인된 단일 조직의 운영 자산 약 2,000개를 macOS 25.1, Burp Suite Professional 2025.10, Python 3.12에서 조사했습니다. 9개 도구를 비교했고, 확장 가능한 도구에는 동일한 6개 사용자 규칙을 적용했으며, 실제 credential의 외부 검증은 승인 범위와 비파괴 기준 안에서 수행했습니다.

ground truth는 194개의 엄격한 비밀값과 249개의 공개 chain-context 식별자를 구분했습니다. 194개는 APIM 키 54, client secret 50, CryptoJS 암호문 37, 기타 API/token 29, JWT 11, Google 키 6, CyberArk AIM 4, 평문 사용자 credential 3으로 구성됩니다.

주요 실험 결과

지표 결과 조건
credential 노출 앱 113/약 2,000, 5.65% 95% CI 4.7–6.8%, 단일 조직
완전한 Azure AD 세트 63/113, 55.8% 95% CI 46.1–65.1%
Azure secret 중 완전 체인 63/86, 73.3% client ID·secret·tenant·resource 결합
CryptoJS 구성 노출 16/113 앱, 37 blob 키가 클라이언트에 공존
SecretSifter 151/194 recall 77.8%, precision 86.3%, F1 0.818 9개 운영 도구 중 최고
TruffleHog 71/194 recall 36.6%, precision 89.9%, F1 0.520 런타임 응답 corpus
수동·모델 보조 참조 166/194 recall 85.6%, F1 0.851 Claude Opus 4.7, 탐지기 아님

나머지 도구의 true positive는 SecretFinder 63, JSluice 62, Titus 40, JSMiner 12, Nuclei 7, Sensitive Data Exposure Discovery 7, Cariddi 2였습니다. 27/194인 13.9%는 수동 분석에서만 확인되어 자동 스캐너 조합의 coverage가 약 86.1%에서 정체됐고, McNemar 비교는 주요 도구 차이에 대해 p<0.001을 보고합니다.

실제 발견된 취약점 / 사례

첫 사례에서는 번들에 client ID·secret·resource URI·APIM key가 함께 있었고, 로그인 리다이렉트에서 tenant ID를 얻었습니다. 연구진은 애플리케이션 토큰 발급, 사용자 프로필 반환, 비밀번호 재설정 endpoint 존재까지 확인하고 재설정 실행 전 중단했습니다.

두 번째 사례에서는 CryptoJS AES로 암호화된 구성과 키가 같은 클라이언트에 포함됐습니다. 연구진은 이를 복호화해 credential 세트를 회수하고 사용자 프로필 API 접근을 재현했으며, 두 사례 모두 조직에 공개했다고 설명합니다.

저자 주장 vs 실제 증명 범위

운영 프런트엔드 스캐닝이 저장소 스캐닝의 사각지대를 보완하고, credential 조합이 실제 API 접근으로 이어질 수 있다는 주장은 corpus와 두 체인으로 뒷받침됩니다. SecretSifter가 비교 대상 9개 중 가장 높은 recall을 기록한 것도 이 corpus에서는 사실입니다.

그러나 “프로덕션 웹 전반의 일반적 노출률”이나 “어떤 조직에서도 해당 도구가 최선”이라고까지 증명하지는 못합니다. 또한 113개 전부의 exploitability, 장기 유효성, 사용자 계정 탈취 가능성을 입증한 결과도 아닙니다.

기존 공격 / 기존 점검 방식과의 차이

기존 secret scanning은 Git history, 저장소 파일, CI 로그를 중심으로 하고 개별 토큰 패턴을 찾습니다. 이 연구는 최종 HTTP 응답, 동적 chunk, 구성 blob을 보고 public identifier와 secret의 관계를 조합해 “탐지된 문자열이 실제 인증·인가 체인에서 어떤 역할을 하는가”를 평가합니다.

정적 분석만으로는 런타임 주입과 배포 후 변형을 놓칠 수 있고, DAST만으로는 정상 UI가 호출하지 않는 숨은 endpoint를 놓칠 수 있습니다. 논문은 두 계층을 대체 관계가 아니라 빌드 후·운영 단계의 연속 통제로 배치합니다.

연구의 한계와 주의해서 볼 부분

저자가 인정한 한계는 단일 조직·Azure 편중, 무작위 표본 부재, 제3자 스크립트의 ground truth 제외, 동일 앱 내 credential 상관성, 사용자 규칙 overlay의 특수성입니다. 운영 API를 파괴적으로 검증할 수 없기 때문에 잠재 영향과 확인된 영향도 구분해야 합니다.

추가로, 저자 소유 도구와 저자 구축 ground truth를 같은 평가에 사용했고 LLM이 후보 라벨에 참여했습니다. 이 결과는 강한 현장 사례이지만 독립 benchmark나 블라인드 재현 연구와 같은 증거 수준으로 읽어서는 안 됩니다.

공개 PoC / Exploit / Tool / Artifact 분석

공식 SecretSifter 저장소v1.0.1 release는 2026-09-23 확인 시 공개 상태였습니다. 논문 표의 secretsifter/burp-secret-scanner 주소는 404였지만, 저자 조직의 실제 저장소에는 Java 17+, Burp Suite 2024.7+, Gradle build, src, community-rules, evaluation 구조와 로컬 탐지·bulk scan 기능이 설명되어 있습니다.

논문 평가 버전과 일치하는 v1.0.1은 commit f453a3e138928bc94d94afc3728c0872521d0fdb에 대응하고 재현 가능한 JAR build를 명시합니다. 이 도구는 credential 탐지와 보고를 구현하지만, 논문의 두 실제 공격 체인을 자동 exploit하는 공개 PoC는 아니며, 무단 대상에서 유효성 검사나 API 호출에 사용해서는 안 됩니다.

레드팀 / 모의해킹에서 어떻게 활용할까

승인된 범위에서 저장소 스캔 이후 생성된 배포 bundle과 운영 응답을 별도 자산으로 취급합니다. 발견 시 값 자체보다 client secret → token endpoint → audience/resource → APIM key → API authorization 관계를 그리되, 토큰 발급과 API 호출은 최소 권한·비파괴 테스트 계정으로 제한합니다.

관찰 포인트는 동적 chunk, runtime config, source map, 암호화 blob과 키의 공존, login redirect의 tenant 노출, CORS와 무관한 서버 간 호출 가능성입니다. 실데이터가 반환되거나 상태 변경 endpoint가 확인되는 즉시 중단하고 증거 보존·회전·공개 절차로 전환해야 합니다.

실제 점검 시 추가할 체크리스트

  • 빌드 완료 후 배포 아티팩트와 CDN origin을 secret scan하는가
  • client secret·subscription key가 브라우저 응답에 절대 포함되지 않는가
  • public client는 Authorization Code + PKCE를 사용하고 confidential credential을 갖지 않는가
  • 앱 권한이 delegated/minimum scope이고 application-wide 권한이 제거됐는가
  • BFF, managed identity, Key Vault로 서버 측 비밀을 격리했는가
  • CryptoJS 암호문과 복호화 키가 동일 클라이언트에 있지 않은가
  • source map·manifest·lazy chunk·SSR state·오류 응답까지 검사하는가
  • 노출 발견 시 production뿐 아니라 staging·DR의 credential도 회전하는가
  • 발급 토큰, APIM key, 의심 API 호출 로그를 소급 조사하는가
  • 앱 단위로 중복을 묶고 공개 식별자와 실제 secret을 구분하는가

실무 가치 평가

운영 웹 자산을 관리하는 조직에는 가치가 높습니다. 특히 프런트엔드 빌드가 여러 파이프라인·외주 모듈·런타임 구성 서비스를 거치는 환경에서 “repo scan 통과”를 완료 기준으로 삼지 말아야 할 정량적 근거를 제공합니다.

도구 순위와 노출률은 환경 종속적이므로 그대로 KPI로 가져오기보다, 배포 후 검증 단계와 credential chain triage 방법을 채택하는 편이 적절합니다. 우선순위는 탐지기 추가보다 비밀이 클라이언트 경계를 넘지 않는 설계와 최소 권한입니다.

결론

이 논문이 가장 설득력 있게 보여준 것은 비밀 유출이 소스 코드 문제로 끝나지 않고 최종 배포물에서 다시 생긴다는 사실입니다. 브라우저에 전달된 confidential credential은 이미 공개된 것으로 취급하고 즉시 회전해야 하며, 클라이언트 측 암호화나 CORS를 보완책으로 오해해서는 안 됩니다.

실무 방어는 repository scan, post-build artifact scan, runtime response scan, 최소 권한, BFF/managed identity, 로그 기반 사후 검증을 하나의 수명주기로 묶어야 합니다. 연구 수치는 단일 조직 사례라는 한계를 유지해 해석하되, 깨진 신뢰 경계와 대응 방향은 명확합니다.

반응형

댓글