jQuery DOM 기반 크로스 사이트 스크립팅 (DOM XSS)

DOM-based Cross-Site Scripting (DOM XSS)

설명

DOM 기반 XSS는 DOM에서 읽은 텍스트나 속성 값(예: textContent/innerText/value/attr)이 다시 HTML로 해석되어 삽입될 때 발생합니다. jQuery에 사용자 제어 문자열을 $() 인자로 넘기면 HTML로 파싱되거나, .html()/.append()에 문자열을 주면 브라우저가 태그와 이벤트 핸들러를 실행해 스크립트가 동작할 수 있습니다. 이미 이스케이프된 텍스트라도 재해석되면 이스케이프가 무력화되어 공격 코드가 실행될 수 있습니다.

잠재적 영향

  • 세션 탈취 및 사용자 가장: 공격 스크립트가 쿠키/JWT/localStorage를 탈취하거나 사용자를 가장할 수 있습니다.

  • 민감 정보 유출: 화면/폼의 데이터, 입력값, CSRF 토큰 등을 읽어 외부로 전송할 수 있습니다.

  • DOM 변조 및 피싱: 페이지 내용을 바꿔 가짜 입력 폼/팝업을 띄워 자격증명을 수집할 수 있습니다.

  • 임의 요청 전송: 사용자의 권한으로 백엔드 API 호출, 계정 설정 변경 등을 유발할 수 있습니다.

  • 지속적 오염: 속성/Storage/URL에 저장된 값이 반복적으로 재해석되면 재방문 시에도 악성 스크립트가 실행될 수 있습니다.

해결 방법

  • DOM에서 읽은 텍스트/속성 값을 HTML로 직접 해석하지 말고 textContent/innerText 또는 jQuery.text()로 출력하세요.

  • 사용자 제어 문자열을 셀렉터로 사용할 때는 jQuery($str) 대신 $.find(str)을 사용해 HTML 파싱을 피하세요. 가능하면 허용 목록(allowlist)으로 셀렉터를 제한하세요.

  • 불가피하게 HTML을 삽입해야 한다면 DOMPurify 같은 검증된 Sanitizer로 정화한 뒤 사용하세요. 허용 태그/속성은 최소화하세요.

  • jQuery .html()/.append()/.before()/.after()에 문자열을 직접 넘기지 말고, 필요한 경우 document.createTextNode 또는 안전한 DOM 노드를 사용하세요.

  • URL의 query/hash, data-* 속성, input.value 등 사용자 제어 값은 항상 검증/정화 후 사용하세요.

  • 방어 심층(Defense-in-Depth)으로 CSP(Content Security Policy)를 적용해 인라인 스크립트 실행을 차단하세요.

취약한 코드 및 안전한 코드 예시

취약한 코드

안전한 코드

설명:

  • 취약한 코드: attr로 읽은 사용자 제어 문자열(raw)을 .html()이나 jQuery($raw)에 넘기면 브라우저가 이를 HTML로 파싱합니다. 공격자가 같은 payload를 주입하면 이벤트 핸들러가 실행되어 XSS가 발생합니다.

  • 안전한 코드: 텍스트는 .text()로 출력해 HTML 재해석을 차단하고, HTML 삽입이 필요할 때는 DOMPurify로 정화합니다. 사용자 제어 셀렉터는 $.find로만 처리하고 허용 목록으로 제한하여 jQuery의 HTML 파싱 경로를 피합니다.

참조

Last updated