Skip to main content

JavaScript 분석

점검 목적​

브라우저가 내려받는 JavaScript에서 route, API, 입력 처리, 인증·권한 흐름, 파일 처리, 실시간 통신과 설정 단서를 찾는다. 이 문서는 특정 취약점보다 전체 웹 공격 표면을 넓히는 데 목적이 있다. 코드 문자열만으로 취약을 단정하지 않고 실제 브라우저 동작과 서버 응답으로 검증한다.

유형 구분​

유형특징실무 판단
파일·원본bundle, chunk, worker, source map이 원본 구조를 보여줌실제 로드 여부와 추가 노출 내용을 확인
Route·APIURL, HTTP Method, 요청·응답 필드가 포함됨Network 요청과 대조한 뒤 직접 재현
입력·출력URL·메시지·저장값이 DOM·요청·redirect에 사용됨입력 출처와 사용 위치를 연결해 후보 분류
인증·권한토큰 처리, 역할 조건, 숨은 관리자 기능이 포함됨UI 제한과 서버 검증을 분리 확인
기능 흐름주문·가입·승인 단계와 상태값이 포함됨정상 순서와 서버 상태 검증에 활용
실시간·백그라운드WebSocket·GraphQL·worker가 별도 통신을 만듦일반 XHR 목록 밖의 통신까지 추적
설정·키API 주소, 환경명, 공개 키, 토큰 문자열이 포함됨공개 식별자와 사용 가능한 비밀값을 구분

진단 절차​

Step 1. 화면과 Network 기준선 저장​

로그인 전·후와 역할별로 주요 기능을 한 번씩 사용한다. DevTools Network에서 문서, XHR·Fetch, JavaScript, WebSocket 요청을 보존한다.

화면 또는 기능
요청 URL과 Method
요청 body·Header
응답 상태와 주요 필드
요청을 시작한 JavaScript 파일(Initiator)
로그인 상태와 계정 역할

JS 분석만 먼저 하면 사용하지 않는 오래된 코드에 시간을 쓰기 쉽다. 실제 동작하는 요청을 기준점으로 잡고 정적 분석 결과와 연결한다.

Step 2. 실제 로드된 JavaScript 수집​

HTML의 <script src>만 보지 않는다. Network의 JS 필터에서 동적으로 로드된 chunk, worker, lazy-loaded 화면 파일까지 확인한다.

main.*.js
app.*.js
runtime.*.js
chunk-*.js
pages/*.js
service-worker.js
worker-*.js

브라우저에서 확인한 파일만 필요한 범위로 저장한다.

curl -sS 'https://<TARGET>/assets/app.<HASH>.js' -o app.js

Step 3. Source map 확인​

배포된 JS 끝의 sourceMappingURL 주석과 DevTools의 Developer Resources를 확인한다.

//# sourceMappingURL=app.abc123.js.map

명시된 경로가 없을 때만 같은 파일명 뒤에 .map을 붙인 후보를 제한적으로 확인한다.

GET /assets/app.abc123.js.map HTTP/1.1
Host: <TARGET>

Source map JSON에서 볼 값:

필드확인할 것
sources원본 디렉터리와 파일명
sourcesContent원본 코드가 실제 포함됐는지
names함수·변수 이름 단서
sourceRoot원본 경로 기준점

map 파일이 열린다는 사실만으로 취약을 확정하지 않는다. 원본 코드·내부 경로·비밀값·숨은 기능이 추가로 노출되는지 본다.

Step 4. 읽을 수 있는 형태로 정리​

DevTools의 pretty print를 먼저 사용한다. source map이 로드되면 Authored 영역의 원본 파일을 우선 본다. 저장한 JS는 검색 편의를 위해 줄바꿈한 복사본을 사용할 수 있지만, 원본도 함께 보존한다.

검색은 한글 화면명과 실제 요청 필드에서 시작한다.

rg -n -i "fetch\(|axios|/api/|/graphql|wss://|token|authorization|role|admin|redirect|upload|download|innerHTML|postMessage|price|status" app.js

하나의 거대한 정규식 결과를 그대로 endpoint 목록으로 취급하지 않는다. 문자열이 주석·라이브러리·테스트 코드에만 있는지 주변 함수를 함께 읽는다.

Step 5. 입력과 동작을 연결하는 함수 추적​

관심 문자열을 찾으면 값이 어디서 들어오고 어디에 사용되는지 주변 함수를 읽는다.

const next = new URLSearchParams(location.search).get('next');
const token = sessionStorage.getItem('access_token');
api.get(`/api/files/${fileId}`, {headers: {Authorization: `Bearer ${token}`}});
messageBox.innerHTML = serverMessage;

이 코드에서는 다음 후보를 서로 분리해 기록한다.

next가 실제 redirect에 사용되는지
token이 어떤 API와 역할에서 사용되는지
fileId의 소유권을 서버가 확인하는지
serverMessage가 신뢰 가능한 값인지

Step 6. Network와 코드 연결​

화면에서 기능을 다시 실행하고 Network의 Initiator·Call Stack으로 해당 함수를 찾는다. 코드의 기본값과 실제 전송값이 다르면 변환 지점을 따라간다.

코드에서 찾은 값Network에서 확인할 것
API 경로실제 base URL, 버전 prefix, path parameter
body 필드생략되는 값, 기본값, 직렬화 결과
입력 출처URL, DOM, storage, message, API 응답 중 어디서 오는지
사용 위치요청, HTML 삽입, redirect, 파일 경로, 동적 코드 실행 여부
상태 상수요청에 전송되는지 클라이언트 내부에서만 쓰는지
인증 Header브라우저가 토큰을 붙이는 위치
기능 플래그서버 응답인지 로컬 조건인지

Step 7. Burp에서 한 항목씩 검증​

정상 요청을 Repeater로 보내 기준선을 저장한 뒤, JS에서 찾은 값을 한 번에 하나씩 바꾼다.

숨은 endpoint를 현재 세션으로 직접 요청
객체 ID를 다른 테스트 객체로 교체
URL·메시지 입력이 DOM이나 redirect에 반영되는지 확인
화면에 없는 body 필드를 하나만 추가·제거
다른 역할의 테스트 세션으로 같은 요청 전송
업로드·다운로드 파일 식별자를 교체

응답 코드만 보지 않고 화면 실행, 최종 URL, 객체 상태, 다운로드 내용, 권한과 이력을 취약점 문맥에 맞게 확인한다.

상황별 빠른 선택​

현재 상황먼저 볼 위치
API 문서가 없음Network Initiator와 /api/, fetch, axios 검색
관리자 메뉴가 숨겨짐route 목록, admin, role, permission, lazy chunk
URL 입력이 화면에 반영됨location, URLSearchParams, DOM 삽입 함수
파일 기능이 있음upload, download, fileId, filename, MIME 처리
새 창·iframe·외부 이동이 있음postMessage, event.origin, window.open, redirect 함수
가격이 화면에서 계산됨price, amount, total, discount, 주문 생성 함수
다단계 화면route 전환, 상태 상수, nextStep, confirm, complete
bundle이 한 줄로 압축됨pretty print와 source map Developer Resources
초기 JS에 기능 코드가 없음화면을 연 뒤 새로 로드된 chunk 확인
XHR에 요청이 안 보임WebSocket, GraphQL, worker, service worker 확인

페이로드 노트​

1. 파일 구조와 Source map​

이럴 때 사용: minified bundle만으로 원래 파일과 기능 구분이 어렵다.

src/api/users.ts
src/router/admin.ts
src/components/FilePreview.tsx
src/features/payment/confirm.ts
src/config/environment.ts

DevTools의 Authored 영역이나 source map의 sources, sourcesContent에서 원래 구조를 확인한다. 파일명으로 관련 영역을 좁힌 뒤 실제 로드된 코드인지 Network와 연결한다. 개발자 로컬 경로나 컴포넌트 이름만 보이는 경우는 정보 단서로 분리한다.

2. Route·API와 HTTP Method​

이럴 때 사용: 화면에서 호출되지 않는 API나 같은 기능의 다른 Method를 찾는다.

api.get('/api/orders/' + id)
api.post('/api/orders/' + id + '/confirm')
api.patch('/api/orders/' + id)
api.delete('/api/orders/' + id)

확인할 것: 문자열만 추출하지 말고 어떤 계정 상태에서 호출되는지, path·query·body 중 어디에 ID가 들어가는지 기록한다. 직접 요청 결과는 권한 검증 / IDOR와 연결한다.

3. 인증·권한·세션 단서​

이럴 때 사용: 토큰 저장과 갱신, 역할별 메뉴, 관리자 route, 권한 이름이 코드에 보인다.

const token = sessionStorage.getItem('access_token');
if (user.role === 'ADMIN') showAdminMenu();
if (permissions.includes('USER_EXPORT')) enableExport();

토큰의 저장 위치와 API client가 Authorization Header를 붙이는 지점을 확인한다. UI 조건을 바꾸거나 숨은 route를 여는 것만으로 권한 우회가 아니다. 일반 사용자·비인증 세션의 직접 요청이 서버에서 처리되는지는 인증, 세션 관리, 권한 검증 / IDOR에서 확인한다.

4. 입력값의 출처와 사용 위치​

이럴 때 사용: URL·DOM·Web Storage·postMessage·API 응답이 화면 출력이나 이동 함수에 들어간다.

const q = new URLSearchParams(location.search).get('q');
const next = new URLSearchParams(location.search).get('next');
result.innerHTML = q;
location.href = next;
window.addEventListener('message', event => render(event.data));

입력 출처(source)와 위험한 사용 위치(sink)를 한 쌍으로 기록한다. 값이 그 함수까지 실제로 도달하는지 DevTools breakpoint로 확인한다. 문맥에 따라 XSS, Open Redirect, postMessage Origin 검증으로 분기한다.

5. 파일 업로드·다운로드 단서​

이럴 때 사용: 파일 선택, 미리보기, 변환, 내보내기, 다운로드 코드가 있다.

upload('/api/files', formData)
download(`/api/files/${fileId}?name=${filename}`)
previewUrl = URL.createObjectURL(file)

허용 확장자·MIME 목록이 클라이언트에만 있는지, 다운로드 요청에 객체 ID·경로·파일명이 들어가는지 확인한다. 실제 검증은 파일 업로드, Path Traversal / LFI, 권한 검증 / IDOR로 연결한다.

6. 비즈니스 규칙과 상태 전이​

이럴 때 사용: 가격 계산, 쿠폰 조건, 단계 함수, 상태 상수가 코드에 보인다.

const finalPrice = subtotal - coupon.discount + shippingFee;
const allowedNext = {
PENDING: ['PAID', 'CANCELLED'],
PAID: ['SHIPPED', 'REFUND_REQUESTED']
};

클라이언트 계산식과 상태표는 여러 단서 중 하나다. 실제 서버가 같은 규칙을 강제하는지는 비즈니스 로직 결함에서 확인한다.

7. GraphQL과 WebSocket​

이럴 때 사용: 일반 XHR 요청이 적거나 실시간 화면에서 상태가 바뀐다.

client.query({query: GET_DOCUMENT, variables: {id}})
new WebSocket('wss://api.target.example/events')
socket.emit('subscribe', {channelId})

GraphQL operation 이름·variables와 WebSocket event 이름을 기록한다. 실제 handshake, 인증정보, 전송 frame은 Network에서 확인하고 같은 세션 문맥으로 재현한다.

8. Worker와 동적 chunk​

이럴 때 사용: 초기 bundle에는 코드가 없고 특정 화면을 열 때만 기능이 동작한다.

import('./pages/account/settings.js')
new Worker('/assets/export-worker.js')
navigator.serviceWorker.register('/service-worker.js')

해당 화면을 실제로 연 뒤 새로 내려받은 파일을 수집한다. chunk 이름만 보고 관리자 기능 접근을 확정하지 않는다.

9. 설정값·키·토큰 문자열​

이럴 때 사용: API key, DSN, 환경 변수 이름, Authorization 문자열이 보인다.

발견 값기본 판단
API base URL·환경명구조 단서
공개용 지도·분석 키도메인 제한과 사용 목적 확인
Sentry DSN일반적으로 클라이언트 공개 가능, 오용 가능성 별도 확인
비공개 API credential최소 권한의 읽기 요청 등으로 유효성 제한 확인
사용자 access token실제 사용자·만료·권한 범위를 확인

문자열 모양만으로 비밀값이라고 단정하지 않는다. 유효성 확인이 필요해도 대량 조회나 비용이 발생하는 API 호출은 기본 검증에서 피한다.

10. 도구 참고​

  • DevTools Sources의 전체 검색, pretty print, Developer Resources를 먼저 사용한다.
  • LinkFinder·JSFinder·SecretFinder 같은 도구 결과는 후보 목록으로만 사용한다.
  • 도구가 찾지 못한 문자열 결합 URL, runtime base URL, GraphQL operation은 수동으로 확인한다.
  • 분석 대상은 스코프의 실제 로드 파일로 제한하고 무작정 외부 domain 전체를 수집하지 않는다.

우회 매트릭스​

관찰된 증상다음 시도확인할 것
bundle이 한 줄이고 이름이 짧음pretty print, source map, Network Initiator난독화와 단순 minify 구분
source map 주석이 없음DevTools Developer Resources, 명시된 manifest 확인.map 경로 대량 추측은 피함
초기 bundle에 endpoint가 없음기능 화면을 열어 lazy chunk 수집동적 import 여부
API 문자열이 조각으로 결합됨base URL·template literal·호출 함수 추적최종 Network URL
숨은 route가 열리지만 데이터가 없음XHR·Fetch 응답과 서버 권한 확인UI 노출과 권한 우회 구분
endpoint가 404를 반환함Method, prefix, path parameter, 환경 조건 확인오래된 코드일 수 있음
필드를 바꿔도 결과가 같음필드 제거와 후속 조회 비교서버 재계산·무시 가능성
키처럼 보이는 문자열 발견공급자와 키 유형 확인공개 키와 credential 구분

취약 판정 기준​

취약 확정​

  • JS에서 찾은 숨은 API가 일반 사용자 또는 비인증 요청을 서버에서 허용한다.
  • URL·메시지·API 응답이 위험한 DOM·redirect·동적 실행 위치까지 도달해 실제 동작한다.
  • 화면에서만 제한하던 권한·파일·업무 필드를 변조해 서버 상태나 응답 내용이 실제로 바뀐다.
  • source map이나 bundle에 포함된 비공개 credential이 유효하며 스코프 내 자원 접근에 사용된다.
  • 클라이언트에만 있는 검증을 제거해 정상 UI로는 불가능한 중요 동작이 처리된다.

후보 / 보류​

  • 사용하지 않는 API 경로·관리자 route·입력 처리 함수·상태값 문자열만 발견했다.
  • source map이 열리지만 공개된 프런트엔드 원본 외에 민감한 내용은 확인되지 않았다.
  • 공개 목적의 API key·DSN·프로젝트 식별자만 발견했다.
  • 숨은 필드를 전송했지만 서버가 무시하거나 다시 계산한다.

영향 상승 조건​

  • 숨은 기능이 결제·환불·개인정보·관리자 동작과 연결된다.
  • credential이 운영 환경의 비공개 API나 데이터에 접근할 수 있다.
  • JS 단서가 XSS·Open Redirect·파일 처리·IDOR·인증·비즈니스 로직 같은 실제 취약점으로 재현된다.

참고자료​

공식 및 테스트 가이드​

커뮤니티 참고 / 도구​