최근 들어 개발의 편의성을 위해 다양한 프론트엔드 프레임워크를 사용하는 추세이다. 프레임워크를 사용하면 DOM 내의 데이터를 수정하기에 간편하고, 웹 페이지를 컴포넌트화 하여 작성할 수 있기 때문에 개발하는데에 있어서 굉장히 편리해진다. 보편적으로 사용되는 프레임워크의 종류로 Vue, React, AngularJS 등이 존재한다.

Client Side Template Injection은 이용자의 입력 값이 Client Side Template Framework에 의해 템플릿으로 해석되어 렌더링될 때 발생한다. 개발의 편의성을 높여주는 프레임워크지만 잘못된 방식으로 사용할 경우, 이를 통해 XSS 취약점까지 연계하는 것이 가능하다.


Client Side Template Injection (CSTI)

Vue

Vue 혹은 Vue.js라고 불리는 프론트엔드 프레임워크는 2014년 출시된 프레임워크이며, Google의 한 연구원인 Evan You가 개발하였다. Vue는 오픈소스 자바스크립트 프레임워크로, 이용자 인터페이스나 Single Page Application을 빌드할 때 사용된다. Vue에 대한 상세한 정보는 https://vuejs.org/에서 확인할 수 있다.

<script src="<https://unpkg.com/vue@3>"></script>

<div id="app">{{ message }}</div>

<script>
  Vue.createApp({
    data() {
      return {
        message: 'Hello Vue!'
      }
    }
  }).mount('#app')
</script>

{{ }}로 감싸진 부분이 Vue 템플릿 부분이다. 해당 템플릿 내에서 문자열을 표기하거나, 자바스크립트 표현식을 실행할 수 있다. 만약 여기서 템플릿 내부에 공격자의 입력이 들어가 Template Injection 취약점이 발생한다면, XSS 공격으로 이어질 수 있다.

아래 코드는 이용자의 입력을 그대로 페이지에 출력하여 Vue Template Injection에 취약한 예제 소스코드이다.

<script src="<https://unpkg.com/vue@3>"></script>

<div id="app">
	<?php echo htmlspecialchars($_GET['msg']); ?>
</div>

<script>
  Vue.createApp({
    data() {
      return {
        message: 'Hello Vue!'
      }
    }
  }).mount('#app')
</script>

이용자로부터 입력 받은 GET 메소드의 msg 파라미터를 그대로 출력하지만, htmlspecialchars 함수를 통해 꺽쇠 문자가 모두 인코딩되기 때문에 일반적인 XSS 공격은 불가능하다. 하지만 출력되는 값이 Vue의 템플릿으로 사용될 수 있기 때문에 Template Injection이 발생한다.

Vue Template Injection

Vue Template Injection이 발생하는지 확인하는 간단한 방법은 템플릿을 이용해 산술 연산을 수행해보는 것이다. {{1+1}}과 같은 산술 연산 형태의 템플릿을 입력했을 때, 연산이 실행된 형태인 2가 출력된다면 Template Injection이 발생하는 것으로 확인할 수 있다.

ee0f46011c737017eeb7c84f92dc1ee9bb94c130333fe2098c9e8eae2d52e2d5.png

Template Injection이 발생할 때 이를 임의 자바스크립트 코드 실행으로 연계하는 방법으로 보통 생성자 (constructor)를 이용한다. Vue 템플릿 컨텍스트 내에서 생성자에 접근하여 임의 코드에 해당하는 함수를 생성하고, 이를 호출하는 방식으로 XSS 공격이 가능하다.