DOM 조작과 크로스 사이트 스크립팅

terry yoon·2021년 10월 4일
1
post-thumbnail

DOM과 DOM API

브라우저는 서버로부터 자원을 요청하고 이를 받아서 랜더링 엔진에 의해서 파싱 과정을 거쳐 화면에 최종 랜더링을 하게 된다.

이때 서버로부터 받아온 HTML 파일을 파싱하는 과정에서 DOM을 구성하여, HTML의 노드들의 상속 관계를 트리 구조 형태로 만든다고 배웠다. DOM은 단순히 문서의 계층적 구조와 정보 뿐만 아니라, 이를 제어할 수 있는 프로퍼티와 메서드인 DOM API를 제공한다.

이를 통해서 DOM이 만들어지고 화면에 랜더링 된 이후, 자바스크립트 코드에 의해서 해당 DOM의 구조 또는 스타일을 동적으로 변동할 수 있다.

이번 글에서는 노드의 생성과 추가 관점에서 DOM을 조작하는 2가지 메서드를 살펴보고 2가지 메서드의 장단점과 이를 보완하기 위한 방법을 살펴본다.

innerHTML의 문제

Element.prototype.innerHTML

노드 프로토타입 체인 중 Element 프로토타입 객체의 메서드로, getter와 setter로 구성된 접근자 프로퍼티이다.

접근자 프로퍼티는 자체적인 값을 가지고 있지 않고, 객체 내에서 다른 프로퍼티의 값을 취득하거나 변경할 때 호출되는 getter/setter로 이뤄진 프로퍼티

getter를 호출하게 되면 해당 요소 노드의 콘텐츠 영역(시작 태그와 종료 태그 사이) 사이의 HTML 마크업을 모두 문자열로 변환한다.

<body> 
  <div class='container'> hello<span class='element'>Terry</span></div> 
</body> 
<script> 
  const $container = document.getElementByClassName('container')
  console.log($container.innerHTML); 
  // 'hello<span class='element'>apple</span>'
</script> 

이 때 innerHTML에 문자열을 할당하게 되면, 해당 요소 노드의 모든 자식 노드는 제거되고 해당 문자열이 HTML 마크업으로 파싱되어 요소노드의 자식노드로 생성된다.

innerHTML 의 장점과 단점

이 방법은 굉장히 단순히 문자열로 DOM을 추가하거나 조작할 수 있다는 장점이 있다.

그러나 이렇게 사용자로부터 입력받은 데이터를 바로 innerHTML의 데이터로 전달하여 파싱하는 과정은 외부 공격(크로스 사이트 스크립팅 공격)에 취약할 수 있다.

innerHTML 이외의 Element.prototype.insertAdjacentHTML 메서드 역시 사용자로부터 입력받은 문자열을 HTML로 파싱하기 때문에, 동일한 취약점을 가지고 있다.

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

크로스 사이트 스크립팅은 웹 어플리케이션에서 어플리케이션 관리자가 아닌 악성 유저가 일부로 심어놓은 악성 코드를 실행하게 함으로써 발생하는 취약점이다. 악의적인 사용자는 공격하려는 사이트에 다른 유저로 하여금 악의적인 스크립트를 실행하도록 유도하여 정보를 편취하거나 의도치 않는 행동을 유발하게 한다.

XSS에는 다음과 같은 유형이 있다. (참고 블로그)

  1. Reflected XSS

    • 해커가 사용자로 하여금 악성 링크를 클릭하도록 유도하여 정보를 탈취하는 방법이다. 일반적으로 메일 또는 문자 등에 악성 URL를 전송한 후, 사용자가 해당 링크를 클릭하면 악성 스크립트가 실행된다.
    • 일반적으로 사용자가 해당 URL을 읽고 잘못된 URL이라고 판단할 수 있기 때문에 해당 URL을 난독화하여 알아보지 못하도록 만든 후, 접근하도록 유도한다.
  2. Stored XSS

    • 게시판, 쪽지함과 같이 저장된 형태의 게시글에 많이 사용되며, 게시글을 작성할 때 악성 스크립트를 심어서 올려서 해당 스크립트 링크를 클릭하거나 혹은 이미지 태그를 클릭하도록 유도하여 악성 스크립트를 실행시킨다.
    • 이를 통해 지속적인(Persistent) 공격을 할 수 있는 방식으로, 일반적으로 stored XSS가 막혀있는 페이지의 경우, 스크립트 코드가 포함된 게시글은 단순히 텍스트로 인식하여 출력한다.
  3. DOM based XSS

    • 사용자 브라우저에서 서버로 요청하는 과정이 아니라, 브라우저 상에서 DOM을 구축하는 과정에서 해커가 해당 DOM 환경을 악의적으로 수정하여 이를 통해 예상치 못한 코드를 실행하도록 만드는 공격 방식입니다.

크로스 사이트 스크립팅 예방하기

DOMPurify 라이브러리

DOM Purify는 2014년 2월에 처음 만들어졌으며, 모던 브라우저에서 호환되되는 노드 패키지이다. 이 패키지를 이용하면 악의적인 코드를 안전한 코드로 만들 수 있다.

1) 클라이언트 사이드

<script type="text/javascript" src="src/purify.js"></script>
const $element = document.getElementByClassName('conatiner'); 

let dirty = '<img src="x">'
$element.innerHTML = DOMPurify.sanitize(dirty); 

2) Node.js 환경

$npm install dompurify 
const createDOMPurify = require('dompurify');
const { JSDOM } = require('jsdom');

const window = new JSDOM('').window;
const DOMPurify = createDOMPurify(window);

const clean = DOMPurify.sanitize(dirty);

직접 생성

Document.prototype.createElement(tagName)는 태그 이름을 통해서 새로운 노드를 생성한다.

const $li = document.createElement('li');

생성한 노드는 DOM에 추가되지 않고 홀로 존재하는 상태이다.

이후 Node.prototype.appendChild(childNode) 메서드를 통해 해당 노드를 DOM 트리 상에서 특정 요소노드의 자식 노드로 붙혀준다.

$elelement.appendChild($li); 

[참고 자료]

XSS 종류
DOM Based XSS
자바스크립트 Deep Dive - 이웅모

profile
배운 것을 기록하는 FrontEnd Junior 입니다

0개의 댓글