📄 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)
  • 기법: 문자열 종료 후 함수 종료 → 공격구문 실행 → 더미 함수로 나머지 감싸기

실습 단계:

  1. 원래 코드 구조 파악

    • function fnEdit(_board_id) 내부에서 document.location.href에 [입력값] 직접 반영
  2. 단순 문자열 주입 테스트 (eqstxss) → 정상 문자열로 반영됨 확인

  3. 문자열 종료 및 코드 실행 주입

    • 주입값: eqstxss’; alert(‘xss’); var test=’
    • 작은따옴표(’)로 문자열 종료 → 세미콜론(;)으로 구문 분리 → alert 실행
  4. 함수 종료를 포함하는 주입 (최종 성공)

    • 주입값: 19’;} alert(‘xss’); function qwer() { var qwer=’
    • 작은따옴표(’) → 문자열 종료, 중괄호(}) → 함수 종료, alert 실행, 더미 함수로 나머지 감싸기
  5. 최종 실행 결과

    • 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

실습 단계:

  1. 기존 JS 구조 파악 및 컨텍스트 탈출 방식 재확인 (문제 2번과 동일한 구조)

  2. location.href 방식 테스트

  3. fetch를 이용한 백그라운드 탈출 (피해자 페이지 변화 없음 → 핵심 기법)

  4. URL 인코딩 후 요청 전송

    • board_id 파라미터에 URL 인코딩된 페이로드 삽입
  5. webhook.site 대시보드에서 수신된 쿠키값 확인

    • 수신 결과: 35bdfac8ace3ff45e9c1a2333356651e

쿠키 탈취 동작 방식:

  1. 피해자가 공격구문이 포함된 URL 클릭
  2. JS 컨텍스트 탈출 후 fetch() 가 백그라운드로 실행됨
  3. document.cookie 의 세션ID 값이 webhook URL의 쿼리 파라미터로 전송됨
  4. 공격자가 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=[값] (세션 기반 인증)

실습 단계:

  1. 필터 규칙 분석

    • content.replaceAll("<”, “”) → ‘<‘만 제거되고 ‘>‘는 그대로 남음
  2. 필터 우회 테스트

    • 입력: <>alert(‘xss’); → 결과: >alert(‘xss’); (’< ‘만 제거됨 확인)
    • 입력: