펜리젠트 헤더

프론트엔드 보안: 업데이트된 DOM 기반 XSS 치트 시트

소개

DOM 기반 XSS 치트 시트는 다음과 같습니다. 자주 사용하는 참조 를 사용하여 클라이언트 측 스크립트 인젝션에 대한 보호 기능을 찾고, 방지하고, 자동화할 수 있습니다. 본질적으로 사용자가 제어하는 입력( 출처)가 위험한 API( 싱크), 안전한 패턴으로 대체( 텍스트 콘텐츠, createElement또는 소독제)를 사용하고 빌드, 런타임 및 펜테스트 워크플로에 검사를 통합하세요. DOM XSS는 전적으로 브라우저에서 발생하고 기존의 많은 서버 측 필터를 우회하기 때문에 프론트엔드가 최후의 방어선이 되며, 대부분의 팀에서 여전히 자동화가 부족한 곳이기도 합니다.

DOM 기반 XSS란 무엇이며 왜 중요한가?

포트스위거에 따르면, DOM 기반 교차 사이트 스크립팅은 다음과 같은 경우에 발생합니다. "JavaScript는 URL과 같이 공격자가 제어할 수 있는 소스에서 데이터를 가져와 다음과 같이 동적 코드 실행을 지원하는 싱크에 전달합니다. eval() 또는 innerHTML." portswigger.net OWASP DOM 기반 XSS 방지 치트 시트는 저장/반영된 XSS와의 주요 차이점을 다음과 같이 강조합니다. 런타임 클라이언트 측 인젝션. cheatsheetseries.owasp.org+1

단일 페이지 앱(SPA), 타사 위젯의 과다 사용, 동적 DOM 구축 등 최신 애플리케이션에서는 페이로드가 서버 로그에 도달하지 않을 수 있고, 기존 WAF가 이를 놓칠 수 있으며, 개발자가 다음과 같은 사항을 충분히 고려하지 않는 경우가 많아 위험이 커집니다. 조각 식별자, 포스트 메시지 흐름또는 창.이름와 같은 일반적인 소스를 사용합니다. 이러한 변화를 인식하는 것이 보안 성숙도를 측정하는 첫 번째 단계입니다.

위협 매핑: 소스 → 싱크

보안 코딩은 다음과 같은 멘탈 맵에서 시작됩니다. 출처 (공격자 입력이 들어오는 곳) 및 싱크 (실행이 발생하는 위치). 한 보안 블로그에 요약되어 있습니다: "소스는 웹 페이지에서 사용자 입력을 추가할 수 있는 모든 위치입니다... 싱크는 소스에 삽입된 데이터가 이동하는 곳으로, 위생 처리되지 않으면 DOM 기반 XSS 취약점으로 이어질 수 있습니다." Medium

아래는 워크스테이션과 검토 체크리스트에 보관해야 할 간결한 표입니다:

소스(진입점)싱크(위험한 API)
위치.해시, 위치.검색, URL 검색 매개변수innerHTML, insertAdjacentHTML, outerHTML
postMessage, 창.이름eval(), 새로운 함수(), setTimeout(문자열)
문서 참조자, 로컬 저장소, 세션 저장소setAttribute('on...'), element.src = ...
검증되지 않은 타사 위젯 데이터모든 DOM 삽입 또는 암시적 코드 실행

OWASP가 강조하듯이 단일 기술로는 XSS를 방지할 수 없으며 적절한 싱크, 인코딩, 위생 처리 및 안전한 API를 결합해야 합니다. cheatsheetseries.owasp.org

코드 및 수정 사항이 포함된 실제 공격 패턴

예제 A - URL 조각을 통한 jQuery 선택기 삽입

취약한 스니펫:

js

$(window).on('hashchange', () => {{

const target = $(location.hash); // 사용자 제어

target[0].scrollIntoView();

});

공격자는 https://site/page.html#<img src="x" onerror="alert(1)"> - jQuery는 해시를 HTML/선택기로 취급하고 onerror 트리거.

수정:

js

const raw = 위치.해시.슬라이스(1);

const safeId = /^[A-Za-z0-9_-]+$/.test(raw) ? raw : null;

if (safeId) {

const target = document.getElementById(safeId);

if (target) target.scrollIntoView();

}

키: 유효성 검사, 해시를 HTML이 아닌 식별자로 취급합니다.

예시 B - postMessage → 평가 체인

취약한 스니펫:

js

window.addEventListener('message', e => {

eval(e.data); // 위험한

});

수정된 버전입니다:

window.addEventListener('message', event => {

if (event.origin !== '') 반환합니다;

시도 {

const msg = JSON.parse(event.data);

핸들메시지(msg);

} catch {

console.warn('잘못된 메시지 형식');

}

});

피하기 평가를 클릭하고 출처를 확인하고 안전한 구문 분석을 사용합니다.

예제 C - 마크다운 컨텍스트에서 편집기/미리보기 XSS

취약한:

js

preview.innerHTML = marked(userInput);

보안:

js

'dompurify'에서 DOMPurify를 가져옵니다;

const dirty = marked(userInput);

const clean = DOMPurify.sanitize(dirty);

preview.innerHTML = clean;

사용자 생성 HTML을 허용하는 경우 위생 처리가 필요합니다.

배포 가능한 구현: 운영 가능 상태로 만들기

안전한 DOM 도우미 - safe-dom.js

js

'dompurify'에서 DOMPurify를 가져옵니다;

export 함수 setSafeHTML(el, dirty) {

const clean = DOMPurify.sanitize(dirty, {

ALLOWED_TAGS: ['b','i','a','p','ul','li','code','pre','img'],

ALLOWED_ATTR: ['href','src','alt','title','rel'],

FORBID_ATTR: ['onerror','onclick','style']

});

el.innerHTML = clean;

}

내보내기 함수 setText(el, text) {

el.textContent = 문자열(text ?? '');

}

export 함수 safeSetAttribute(el, name, val) {

if (/^on/i.test(name)) throw new Error('이벤트 핸들러 속성이 허용되지 않습니다');

el.setAttribute(이름, 문자열(값));

}

이 라이브러리를 사용하여 안전한 DOM 작업을 중앙 집중화하고 인적 오류를 줄이세요.

정적 적용 - ESLint 샘플

js

// .eslintrc.js

규칙: {

'제한되지 않은 구문': [

'오류',

{ selector: "AssignmentExpression[left.property.name='innerHTML']", 메시지: "safe-dom.setSafeHTML 또는 textContent를 사용하세요." },

{ selector: "CallExpression[callee.name='eval']", message: "Avoid eval()" },

{ selector: "CallExpression[callee.property.name='write']", message: "문서.write()를 피하세요." }

]

}

사전 커밋 후크와 결합(허스키, 보푸라기 단계)를 사용하여 위험한 패턴을 차단합니다.

CI/퍼펫티어 테스트 - GitHub 액션

.github/workflows/dom-xss.yml 를 누르면 퍼펫티어 테스트가 트리거됩니다:

// tests/puppeteer/dom-xss-test.js

js

const puppeteer = require('puppeteer');

(async ()=>{

const browser = await puppeteer.launch();

const page = await browser.newPage();

const logs = [];

page.on('console', msg => logs.push(msg.text()));

await page.goto(${URL}/page.html#<img src="x" onerror="console.log("xss")">);

await page.waitForTimeout(1000);

if (logs.some(l=>l.includes('XSS'))) process.exit(2);

await browser.close();

})();

탐지 기반 실패 빌드.

런타임 모니터링 - MutationObserver

js

(function(){

const obs = new MutationObserver(muts=>{{

muts.forEach(m=>{{

m.addedNodes.forEach(n=>{{

if(n.nodeType===1){

const html = n.innerHTML || '';

if(/on(error|click|load)|<script\\b/i.test(html)){

navigator.sendBeacon('/_monitoring/xss', JSON.stringify({

URL: location.href, 스니펫: html.slice(0,200)

}));

}

}

});

});

});

obs.observe(document.documentElement, {childList:true, subtree:true});

})();

예기치 않은 DOM 주입을 경고하는 스테이징에 유용합니다.

브라우저 보안 강화 - CSP 및 신뢰할 수 있는 유형

CSP 헤더:

pgsql

Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-XYZ'; object-src 'none'; base-uri 'self';

신뢰할 수 있는 유형 스니펫:

js

window.trustedTypes?.createPolicy('safePolicy', {

createHTML: s => { throw new Error('직접 HTML 할당이 차단됨'); },

createScript: s => { throw new Error('직접 스크립트 생성 차단됨'); }

});

이렇게 하면 기본적으로 신뢰할 수 없는 싱크가 거부됩니다.

타사 스크립트 안전 - SRI

bash

openssl dgst -sha384 -binary vendor.js | openssl base64 -A

사용 <script src="vendor.js" integrity="sha384‑..." crossorigin="anonymous"></script> 를 클릭하여 고정하고 확인합니다.

자동화를 위한 Penligent와의 통합

팀에서 Penligent를 사용하는 경우, DOM XSS 보호를 지속적인 파이프라인으로 업그레이드할 수 있습니다. Penligent의 연구 문서에서는 다음과 같은 방법을 설명합니다. "런타임 오염 추적을 통한 DOM 기반 XSS 탐지... 서버 측 기술은 클라이언트 측 인젝션을 안정적으로 포착할 수 없습니다." 펜리전트

워크플로 예시:

  1. CI에서 규칙 집합으로 Penligent 스캔을 트리거합니다. dom-xss와 같은 페이로드를 제공합니다. #<img src="x" onerror="alert(1)">.
  2. Penligent는 헤드리스 플로우를 실행하고 PoC를 생성하며 웹훅을 통해 결과를 반환합니다.
  3. CI 분석 결과: 심각도가 높음 이상인 경우 빌드에 실패하고 페이로드 + 싱크 + 수정 권장 사항(예: 'replace innerHTML 와 함께 safe-dom.setSafeHTML).
  4. 개발자가 수정하고 CI를 다시 실행한 후 녹색일 때만 병합합니다.

이렇게 하면 참조(이 치트 시트) → 코드 정책 → 자동 감지 → 체계적인 수정으로 이어지는 루프가 닫힙니다.

결론

프런트엔드는 더 이상 "단순한 UI"가 아닙니다. 그것은 공격 표면. 이 치트 시트는 클라이언트 측 인젝션 이해, 위험한 싱크 교체, 안전한 헬퍼 라이브러리 구축, 정적/CI/런타임 탐지 배포, Penligent와 같은 플랫폼으로 자동화하는 방법을 안내합니다. 다음 단계: 코드베이스에서 금지된 싱크가 있는지 스캔하세요(innerHTML, 평가)를 채택하고 safe-dom 라이브러리, 린트 규칙 적용, 헤드리스 테스트와 실제 펜테스트 로직 통합, 프로덕션/스테이징 모니터링, 써드파티 리소스 고정 등의 기능을 제공합니다. DOM XSS를 보호하는 방법은 다음과 같습니다. 불가능 우연에 의존하는 것이 아닙니다.

게시물을 공유하세요:
관련 게시물
ko_KRKorean