본문으로 건너뛰기
SDETRole
SDETRole

용어집 · 보안

크로스 사이트 스크립팅(XSS)

영어: Cross-site scripting

다른 이름: XSS, 크로스사이트 스크립팅, 사이트 간 스크립팅, 저장형 XSS

정의

신뢰할 수 없는 입력이 다른 사용자의 브라우저에서 실행 가능한 스크립트로 렌더링되어, 공격자가 그 사용자인 척 행동할 수 있게 되는 취약점입니다.

크로스 사이트 스크립팅(Cross-site scripting, XSS)은 애플리케이션이 한 사용자의 입력을 적절한 인코딩 없이 페이지에 넣어서, 브라우저가 그것을 텍스트가 아닌 HTML이나 JavaScript로 취급할 때 발생합니다. 그러면 스크립트가 취약한 사이트에서 피해자의 세션으로 실행되어 페이지 데이터를 읽거나, 사용자로서 요청을 보내거나, 사용자가 보는 화면을 바꿀 수 있습니다. OWASP Top 10 2021에서는 A03 Injection에 포함됩니다.

세 가지 유형

  • 저장형(Stored). 페이로드가 저장되어(댓글, 프로필 이름, 고객 지원 티켓) 그것을 보는 모든 사람에게 전달됩니다. 보통 가장 심각합니다.
  • 반사형(Reflected). 페이로드가 요청에 담겨 있고(주로 검색어 같은 URL 파라미터), 응답에 그대로 되돌아옵니다.
  • DOM 기반(DOM-based). 클라이언트 측 JavaScript가 공격자가 제어하는 데이터(예: location.hash)를 읽어 innerHTML 같은 안전하지 않은 싱크(sink)로 페이지에 씁니다.

테스터가 확인하는 것

나중에 화면에 표시되는(나에게, 다른 사용자에게, 백오피스의 관리자에게) 모든 필드에 무해한 마커를 넣고, 그것이 텍스트로 돌아오는지 살아 있는 마크업으로 돌아오는지 확인합니다. 다음은 권한을 받은 테스트에서만 사용하는 Playwright 자동화 검사입니다.

import { test, expect } from '@playwright/test';

test('comment body is rendered as text, not HTML', async ({ page }) => {
  const probe = '<img src=x onerror="window.__xssProbe=1">';

  await page.goto('/posts/1');
  await page.getByLabel('Comment').fill(probe);
  await page.getByRole('button', { name: 'Post comment' }).click();

  // Escaped output shows the literal characters on screen
  await expect(page.getByText(probe)).toBeVisible();
  // and the handler never ran
  expect(await page.evaluate(() => (window as any).__xssProbe)).toBeUndefined();
});

일반 HTML 외의 출력 컨텍스트도 확인하세요. 속성 값 안, 인라인 스크립트 안, URL(javascript: 링크), 리치 텍스트 에디터는 각각 다른 인코딩이 필요합니다.

검증해야 할 방어 수단

  • 기본 출력 인코딩. 최신 프레임워크(React, Angular, Vue)는 텍스트를 자동으로 이스케이프합니다. dangerouslySetInnerHTML, v-html, innerHTML 같은 탈출구를 찾아보세요.
  • 마크업을 실제로 허용하는 기능에는 HTML 새니타이징(sanitization).
  • 두 번째 방어선으로 인라인 스크립트를 차단하는 Content Security Policy 헤더.
  • HttpOnly 세션 쿠키. XSS가 성공해도 세션 쿠키를 그냥 읽을 수 없도록 합니다.

소유하지 않았거나 서면으로 테스트 허가를 받지 않은 시스템에서는 절대 테스트하지 마세요.

SDETRole 전체에서 검색할 내용을 입력하세요.

Pagefind 전문 검색 · 브라우저에서 실행됩니다 검색 페이지 열기 →