XSS, URL Encoding

XSS, URL Encoding

Tags
Network
Web Dev
Published
April 20, 2025
Author
Seongbin Kim
작성 중
 

1. XSS

 

1-1. 정의

  • XSS는 Cross Site Scripting의 약자로, 외부 스크립트를 실행할 때 발생 가능한 취약점을 의미.
  • CVE에 현재 35,000개 이상의 취약점이 등록.
    • notion image
 

1-2. XSS 공격의 종류 3가지

  • XSS에는 Reflected, Stored, DOM-based가 있고, 각각 반사형, 저장형, DOM 기반형이라고 합니다.
  • 반사형(비지속형)
    • 희생자: 공격자가 배포한 URL로 접속한 사용자
    • 방법: URL에 실행할 HTML/JS을 포함시켜 사용자가 해당 URL을 통해 접속 시 서버에서 생성된 페이지에 포함되어 해당 코드가 실행
  • 저장형(지속형)
    • 희생자: 공격자가 업로드한 스크립트를 실행하는 사용자 (게시판 상세 페이지 등)
    • 방법: 게시판 등 User Content Upload가 가능한 곳에 스크립트를 업로드하고 실행
  • DOM 기반형
    • (반사형과 유사)
    • 희생자: 공격자가 배포한 URL로 접속한 사용자
    • 방법: URL의 해시(#) 값이나 쿼리 스트링의 값에 js를 포함시키면 사용자가 해당 URL을 통해 접속 시 클라이언트 JS에서 해당 코드를 실행
 

1-3. 공격 방식은 ‘수동적‘

  • 웹 공격의 2종류인 능동적 공격, 수동적 공격 중 수동적 공격에 포함
    • 능동적 공격: 공격자가 직접 공격을 실행
      • (ex) SQL Injection, OS Command Injection
    • 수동적 공격: 공격자의 유도를 받아 사용자가 접근해서 실행
      • (ex) CSRF, XSS, Open Redirection, 클릭재킹
 

2. XSS로 악용 가능한 작업

  • 전역 객체로 접근 가능한 선에서 모든 일이 가능
 

2-1. JavaScript 실행을 통해 할 수 있는 일

  • 사용자의 보안 정보를 탈취(공격자 서버로 전송)
  • 기존 form의 기능을 변경하거나 가짜 form을 생성해 피싱
  • 직접 임의의 요청을 실행
  • DOM 이벤트 리스너를 통해 React 인스턴스에 접근
 

2-2. In-memory로 보관한 AccessToken은 안전?

  • in-memory로 accessToken을 보관하는 경우 추적이 어려울 것으로 보았지만, fetch를 monkey-patch 한다면 여전히 config에 대한 interceptor를 작성 가능 (아래는 예시)
    • // 기존 fetch 백업 const originalFetch = window.fetch; // monkey-patch window.fetch = function (...args) { const [resource, config = {}] = args; // 요청 전 config 가로채기 const method = config.method; const headers = config.headers; const body = config.body; console.log(method, headers, body); // 원래 요청 실행 return originalFetch.apply(this, args); };
  • YouTube에서 세션 토큰이 찍힘을 확인 가능
    • notion image
 

3. 방어 방법

 

3-1. HTML/JS Sanitization

  • DOMPurify 라이브러리를 활용하면 안전한 escape이 가능
    • (ex) <, > —> lt, gt
import DOMPurify from 'dompurify'; const clean = DOMPurify.sanitize('<b>hello there</b>');
 

3-2. httpOnly Cookie

  • JavaScript로 아예 접근할 수 없게
 

3-3. javascript URI Scheme 제한

  • href 같은 속성에서는 Javascript URI Scheme도 사용 가능
    • <a href="javascript:alert('hello')" />
    • href 속성에 삽입 전 URI Scheme을 확인하여 필터링 가능
 

4. 번외: URL Encoding

 

4-1. HTML, JS를 URL에 넣을 수 있을까?

  • 가능
  • UTF-8 상에서 표현할 수 있는 모든 문자열, 즉 컴퓨터에서 표현할 수 있는 모든 문자열이 표현 가능하기 때문
 

4-2. URL로 모든 문자열을 표현하는 방법

  • URL에는 모든 문자열이 들어갈 수 있지만, URL 자체는 ASCII만 표현 가능
  • 따라서 ASCII 이외의 문자열은 UTF-8 인코딩 상의 각 바이트를 16진수로 변환해 문자열로 인코딩하는데, 이를 퍼센트 인코딩이라고 지칭
    • (ex) "한"%ED%95%9C
 

4-3. UTF-8 인코딩

  • UTF-8은 가변 문자열 인코딩으로, 1바이트(=ascii)~4바이트까지 가변 바이트수로 문자열을 표현 가능
  • 첫 바이트 문자, 다음 바이트들 문자…
    • 첫 바이트
      • 0 → 1바이트 → ascii (0~127 7bit)
      • 110 → 2바이트
      • 1110 → 3바이트 (0xED, 0x95, 0x9C)
        • → 10진수 숫자 → 10만 → 3바이트 (2바이트=65535?)
        • 0xED = 8bit
          • 1110 _ _ _ _ ← 4비트 낭비
          • 10 _ _ _ _ _ _
          • 10 _ _ _ _ _ _
          • 24bit 중 8bit 낭비 (30% 낭비)
      • 11110 → 4바이트
    • 10
 

4-4. UTF-16

  • 사용처: Java Source Code, … Android,… UTF-16
  • 최초 목표: 2바이트로 모든 걸 표현
  • 현재는 가변 바이트 - 2바이트, 4바이트 (이모지 - 15만개? 2바이트 표현x)
    • (110110 _ _ + 1byte) + (110111 _ _ + 1byte)
    • 장점: 한글이 2바이트안에 표현 가능