๐ What is Client Side Template Injection?
ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ๋ฉด DOM ๋ด์ ๋ฐ์ดํฐ๋ฅผ ์์ ํ๊ธฐ์ ๊ฐํธํ๊ณ , ์น ํ์ด์ง๋ฅผ ์ปดํฌ๋ํธํ ํ์ฌ ์์ฑํ ์ ์๊ธฐ ๋๋ฌธ์ ๊ฐ๋ฐํ๋๋ฐ์ ์์ด์ ๊ต์ฅํ ํธ๋ฆฌํด์ง๊ธฐ ๋๋ฌธ์ ํ๋ก ํธ์๋ ํ๋ ์์ํฌ๋ฅผ ์์ฃผ ์ฌ์ฉํฉ๋๋ค. ๋ณดํธ์ ์ผ๋ก ์ฌ์ฉ๋๋ ์ข
๋ฅ๋ก๋ Vue, React, AngularJS ๋ฑ์ด ์กด์ฌํฉ๋๋ค.
CSTI๋ ์ด์ฉ์์ ์
๋ ฅ๊ฐ์ด client side template framework์ ์ํด ํ
ํ๋ฆฟ์ผ๋ก ํด์๋์ด ๋ ํฐ๋ง๋ ๋ ๋ฐ์ํฉ๋๋ค.
๊ฐ๋ฐ์ ํธ์์ฑ์ ๋์ฌ์ฃผ๋ ํ๋ ์์ํฌ์ง๋ง ์๋ชป๋ ๋ฐฉ์์ผ๋ก ์ฌ์ฉ๋ ๊ฒฝ์ฐ, ์ด๋ฅผ ํตํด XSS ์ทจ์ฝ์ ๊น์ง ์ฐ๊ณํ๋๊ฒ์ด ๊ฐ๋ฅํฉ๋๋ค.
Vue (https://vuejs.org/)
์คํ์์ค ์๋ฐ์คํฌ๋ฆฝํธ ํ๋ ์์ํฌ๋ก ์ด์ฉ์ ์ธํฐํ์ด์ค๋ Single Page Application์ ๋น๋ํ ๋ ์ฌ์ฉ๋๋ฉฐ Vue ํน์ Vue.js๋ผ๊ณ ๋ถ๋ฆฝ๋๋ค.
`` ๋ก ๊ฐ์ธ์ง ๋ถ๋ถ์ด Vue ํ
ํ๋ฆฟ ๋ถ๋ถ์ด๋ฉฐ ํด๋น ํ
ํ๋ฆฟ ๋ด์์ ๋ฌธ์์ด์ ํ์ํ๊ฑฐ๋, ์๋ฐ์คํฌ๋ฆฝํธ ํํ์์ ์คํํ ์ ์์ต๋๋ค.
<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์ ์ทจ์ฝํ ์ฝ๋์
๋๋ค.
์ด์ฉ์๋ก๋ถํฐ ์
๋ ฅ๋ฐ์ GET ๋ฉ์๋์ msg ํ๋ผ๋ฏธํฐ๋ฅผ ๊ทธ๋๋ก ์ถ๋ ฅํ์ง๋ง, htmlspecialchars ํจ์๋ฅผ ํตํด ๊บฝ์ ๋ฌธ์๊ฐ ๋ชจ๋ ์ธ์ฝ๋ฉ ๋๊ธฐ ๋๋ฌธ์ ์ผ๋ฐ์ ์ธ 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>
Template Injection์ด ๋ฐ์ํ๋์ง ํ์ธํ๋ ๊ฐ๋จํ ๋ฐฉ๋ฒ์ `` ๊ณผ ๊ฐ์ ์ฐ์ ์ฐ์ฐํํ์ ํ ํ๋ฆฟ์ ์ ๋ ฅํ์ ๋, ๊ฐ์ด 2 ๊ฐ ์ถ๋ ฅ๋๋ค๋ฉด Template Injection์ด ๋ฐ์ํ๋ ๊ฒ์ผ๋ก ํ์ธํ ์ ์์ต๋๋ค.
Template Injection์ด ๋ฐ์ํ ๋ ์ด๋ฅผ ์์ ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋ ์คํ์ผ๋ก ์ฐ๊ณํ๋ ๋ฐฉ๋ฒ์ผ๋ก๋ ๋ณดํต ์์ฑ์(constructor)๋ฅผ ์ด์ฉํ๋น๋ค. Vue ํ
ํ๋ฆฟ ์ปจํ
์คํธ ๋ด์์ ์์ฑ์์ ์ ๊ทผํ์ฌ ์์ ์ฝ๋์ ํด๋นํ๋ ํจ์๋ฅผ ์์ฑํ๊ณ , ์ด๋ฅผ ํธ์ถํ๋ ๋ฐฉ์์ผ๋ก XSS ๊ณต๊ฒฉ์ด ๊ฐ๋ฅํฉ๋๋ค.
Vue ํ
ํ๋ฆฟ ์ปจํ
์คํธ ๋ด์์ ์์ฑ์์ ์ ๊ทผํ๋ ๋ฐฉ๋ฒ์ ์ฌ๋ฌ๊ฐ์ง๊ฐ ์กด์ฌํ์ง๋ง ๋ํ์ ์ผ๋ก `` ๋ฅผ ์ด์ฉํด ์ ๊ทผ์ด ๊ฐ๋ฅํฉ๋๋ค.
{{_Vue.h.constructor("alert(1)")()}}
AngularJS (https://angular.io/docs)
์ต๊ทค๋ฌJS๋ Google์์ ๊ฐ๋ฐํ์ฌ 2010๋
์ถ์๋ ํ๋ก ํธ์๋ ํ๋ ์์ํฌ์
๋๋ค.
AngularJS๋ ํ์
์คํฌ๋ฆฝํธ ๊ธฐ๋ฐ์ ์คํ์์ค ํ๋ ์์ํฌ์ด๋ฉฐ CLI ๋๊ตฌ์์ ๋ค์ํ ๊ธฐ๋ฅ์ ์ ๊ณตํ๊ธฐ ๋๋ฌธ์ ๊ฐ๋ฐ์ ํธ๋ฆฌํ๊ฒ ํด์ฃผ๋ ํ๋ ์์ํฌ ์ค ํ๋์
๋๋ค.
Vue ์ ๋ง์ฐฌ๊ฐ์ง๋ก `` ๋ก ๊ฐ์ธ์ง ๋ถ๋ถ์ด AngularJS ํ
ํ๋ฆฟ ๋ถ๋ถ์ด๋ฉฐ, ํด๋น ํ
ํ๋ฆฟ ๋ด์์ ๋ฌธ์์ด์ ํ์ํ๊ฑฐ๋, ์๋ฐ์คํฌ๋ฆฝํธ ํํ์์ ์คํํ ์ ์์ต๋๋ค.
<!doctype html>
<html ng-app>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script>
</head>
<body>
<div>
<label>Name:</label>
<input type="text" ng-model="yourName" placeholder="Enter a name here">
<hr>
<h1>Hello {{yourName}}!</h1>
</div>
</body>
</html>
AngularJS Template Injection์ ์ทจ์ฝํ ์์ ์์ค์ฝ๋๋ก ์ ๋ ฅ๋ฐ์ GET๋ฉ์๋์ msgํ๋ผ๋ฏธํฐ๋ฅผ ๊ทธ๋๋ก ์ถ๋ ฅํ์ง๋ง, ๊บฝ์ ๊ฐ ๋ชจ๋ ์ธ์ฝ๋ฉ ๋๊ธฐ ๋๋ฌธ์ XSS ๊ณต๊ฒฉ์ ๋ถ๊ฐ๋ฅํ์ง๋ง ์ถ๋ ฅ๋๋ ๊ฐ์ด AngularJS์ ํ ํ๋ฆฟ์ผ๋ก ์ฌ์ฉ๋ ์ ์๊ธฐ ๋๋ฌธ์ Template Injection์ด ๋ฐ์ํ ์ ์์ต๋๋ค.
<!doctype html>
<html ng-app>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script>
</head>
<body>
<?php echo htmlspecialchars($_GET['msg']); ?>
</body>
</html>
AngularJS ํ
ํ๋ฆฟ์์ ์์ฑ์์ ์ ๊ทผํ๊ธฐ ์ํด์๋ `` ๋ก ์ ๊ทผํ ์ ์์ต๋๋ค.
์ด๋ฅผ ์ด์ฉํ์ฌ ์์ ์ฝ๋์ ํด๋นํ๋ ํจ์๋ฅผ ์์ฑํ๊ณ , ํธ์ถํ์ฌ ๊ณต๊ฒฉํ ์ ์์ต๋๋ค.
{{ constructor.constructor("alert(1)")() }}