서론
Document Object Model(DOM)은 브라우저가 HTML 문서를 관리하기 위해 사용하는 객체 모델임.
웹 개발자는 DOM에 이벤트 핸들러를 추가하거나 DOM을 변경하는 방식으로 웹 페이지를 수정하는 것이 가능하다.
DOM은 자바스크립트에서 접근할 수 있도록 각종 API를 제공해 개발자에겐 굉장히 편리한 기능이지만, 이를 잘못 사용할 경우 XSS나 개발자가 의도한 동작과 다르게 동작시킬 수 있는 취약점이 발생할 수 있다.
Document Object Model
Document Object Model (DOM, 문서 객체 모델)이란, 웹 페이지에 대한 프로그래밍 인터페이스이다. 웹 개발자가 작성한 웹 문서는 브라우저에서 파싱되어 DOM으로 표현된다. 자바스크립트가 웹 문서에 접근할 때는 DOM을 통해 접근하게 되며, 일반적으로 DOM에서 제공하는 API를 이용한다.
DOM 내에서 웹 개발자가 작성한 HTML 문서는 트리 형태가 되어 노드로 표현된다.
그리고 해당 노드들은 자바스크립트에서 접근할 수 있게 된다.
var elem = document.getElementById("name");
elem.innerText = "My name is dream";
var div_elem = document.createElement("div");
var text_node = document.createTextNode("Welcome to dreamhack");
div_elem.appendChild(text_node);
document.getElementById 함수를 이용해 미리 정의되어 있던 name이라는 id의 Element를 가져와 innerText를 변경해 실제 웹 문서의 내용을 변경할 수 있다.
또한, document.createElement 함수로 새로운 Element를 생성하는 것도 가능하며, document.createTextNode 함수를 이용해 텍스트 노드를 생성하고, Element에 추가하여 웹 문서에 새로운 내용을 추가할 수 있다.
Dom Clobbering
Dom Clobbering은 id, name 등 HTML에서 이용되는 식별자 속성을 이용해 자바스크립트에서 접근 가능한 DOM 객체들의 속성 및 메소드 등을 변조하는 기법임.
기존 브라우저는 스크립트 작성자의 편의를 위해 DOM 노드 (element 등)에서 자식 노드에 직접 접근할 수 있도록 해왔다. 웹 프로그래밍을 공부하다 보면 document.getElementById()를 사용하지 않고도 노드 id를 변수처럼 사용할 수 있음을 알게 되는데, Window 전역 객체는 자바스크립트 Proxy와 유사한 형태로 구현되어 있어 정의되지 않은 속성을 DOM에서 찾게 된다.
예를 들어 DOM 내에 <a id="link1" href="https://host">host</a> element가 정의되어 있을 때, 자바스크립트에서 별도 변수 정의 없이 link1에 접근하면 해당 요소를 DOM에서 찾는다.
이는 웹 개발자 입장에서는 편리한 기능일 수 있으나, 만약 HTML 마크업이 사용자나 제삼자로부터 제공된다면 문제가 발생할 수 있다. 글로벌 변수 이름공간이나 요소 객체 속성은 미리 정의된 속성 / 함수와 충돌할 수 있으며, 프로그래머가 예상했던 것과 다른 값이 반환되게 된다.
기존 innerHTML 속성의 경우, 요소 내부의 HTML 콘텐츠를 string 형태로 반환하지만 아래 사진과 같이 DOM Clobbering을 이용하게 되면 input 요소 자체를 반환하게 된다.

만약 웹 어플리케이션이 미리 정의되지 않은 전역 변수에 접근한다면 공격자가 입력한 요소로 대체되어 반환될 수 있다.
DOM Clobbering 방어
Dom Clobbering을 방어할 수 있는 가장 효과적인 방법은 간접적 메소드 호출 및 접근자를 사용하는 것임.
HTMLFormElement.prototype.reset.call(elm)
Object.getOwnPropertyDescriptor(Node.prototype, 'textContent').set.call(elm, '')
위와 같은 코드의 형태를 활용하면 실제 객체에 어떤 속성이 정의되었느냐에 상관없이 본래 속성을 접근할 수 있게 된다.
그럼에도 불구하고, third-party 라이브러리와의 상호작용에서 취약점이 발생할 가능성이 높은데, id, name 등 식별자 attribute를 제거할 수 있는 DomPurify와 같은 라이브러리를 사용하는 것이 좋음.
Dom-based XSS
XSS 취약점은 일반적으로 서버에서 이용자의 데이터를 제대로 검증하지 않거나, 필터링하지 않은 채 HTML 문서에 포함시켜 발생하지만, DOM-based XSS는 클라이언트, 즉 자바스크립트 단에서 이용자의 데이터를 가져와 사용하다가 XSS 취약점이 발생한다.
DOM-based XSS는 대표적으로 자바스크립트에서 URL의 파라미터나 해시를 가져와 innerHTML, outerHTML, insertAdjacentHTML과 같이 HTML에 마크업을 삽입할 수 있도록 해주는 기능에서 발생함.
var name_el = document.getElementById("name");
name_el.innerHTML = `My name is ${decodeURIComponent(location.hash.slice(1))}.`;
만약 다음과 같이 자바스크립트에서 URL의 해시 값을 가져와 URL Decoding 후, 문서에 HTML 형태로 삽입한다면 URL 해시에 XSS 공격 코드를 넣어 임의 자바스크립트를 실행할 수 있다.
즉, https://host/domxss.html#<img src=@ onerror=alert(1)>처럼 공격 코드를 작성할 수 있다.
이 때, innerHTMl로 스크립트를 삽입할 때는 <script> 태그를 이용한 자바스크립트 실행은 불가능하기 때문에 반드시 event 핸들러를 이용해 자바스크립트를 실행해야 한다.
'웹해킹 > 개념' 카테고리의 다른 글
| 웹해킹 개념 복습 (1) | 2025.07.01 |
|---|---|
| [Dreamhack-web] Exploit Tech: XS-Search (1) | 2024.12.12 |
| [Dreamhack-web] Exploit Tech: Relative Path Overwrite (1) | 2024.12.12 |
| [Dreamhack-web] Exploit Tech: CSS Injection (1) | 2024.12.11 |
| [Dreamhack-web] Exploit Tech: Client Side Template Injection (1) | 2024.12.11 |