Contenu connexe
Similaire à Vue.js で XSS (20)
Vue.js で XSS
- 6. Vue.js とは?
“Vue (発音は / v j u ː / 、 view と同様)は
ユーザーインターフェイスを構築するための
プログレッシブフレームワークです。他の一
枚板(モノリシック: monolithic)なフレーム
ワークとは異なり、Vue は少しずつ適用して
いけるように設計されています。”
- 公式サイト(jp.vuejs.org)から引用
6
- 16. Vue.js に XSS が入るパターン
v-pre
v-bind
SSR(Mustache)
domProps
compile
16
- 17. Vue.js に XSS が入るパターン
v-pre
v-bind
SSR(Mustache)
domProps
compile
17
- 22. v-html
v-htmlに <img src=. onerror=“alert(1)”> が反映され、
アラートが発動します。
<div id="app">
<p><span v-html="msg">
<img src=. onerror="alert(1)">
</span></p>
<input v-model="msg">
</div>
<script>
new Vue({
el: '#app',
data: {
msg: '<img src=. onerror="alert(1)">'
}
})
</script>
22
<img src=. onerror="alert(1)">
- 30. v-bind
対策
ユーザーの入力値を出力する箇所ではv-bindを使わないように
します
どうしても入力値に応じた出力が必要な場合は、算出プロパ
ティ(computed)で間接的に値を渡すのがよさそうかなと思っ
ています。こういうことやってるよ!等、詳しい方いたら教え
てください。
補足
v-bind:href 以外にも、下記で似たような動作を確認しました
v-bind:onmouseover
v-bind:onfocus
v-bind:onblur
v-bind:onerror
onclick等、他にもあると思います
30
- 31. Vue.js に XSS が入るパターン
v-pre
v-bind
SSR(Mustache)
domProps
compile
31
- 33. SSR
(Mustache)
ここでXSSが発動します。
<?php $name = $_GET['name'] ?? "default"; ?>
~略~
<div id="app">
<p>
ようこそ
<?=htmlspecialchars($name, ENT_QUOTES, "UTF-8") ?>
さん
</p>
<p><a href="?name={{%20alert(1)%20}}">demo</a></p>
</div>
<script>
new Vue({
el: '#app',
data: {
msg: 'test'
}
})
</script>
33
- 34. SSR
(Mustache)
初期表示だとこんな感じです。
<?php $name = $_GET['name'] ?? "default"; ?>
~略~
<div id="app">
<p>
ようこそ
default
さん
</p>
<p><a href="?name={{%20alert(1)%20}}">demo</a></p>
</div>
<script>
new Vue({
el: '#app',
data: {
msg: 'test'
}
})
</script>
34
- 35. SSR
(Mustache)
リンクをclickします。
<?php $name = $_GET['name'] ?? "default"; ?>
~略~
<div id="app">
<p>
ようこそ
default
さん
</p>
<p><a href="?name={{%20alert(1)%20}}">demo</a></p>
</div>
<script>
new Vue({
el: '#app',
data: {
msg: 'test'
}
})
</script>
35
- 38. Vue.js に XSS が入るパターン
v-pre
v-bind
SSR(Mustache)
domProps
compile
38
- 40. domProps
ここでXSSが発動します。
<?php
$users = array( "1" => array("user_name"=>"default"),
"2" => array("user_name"=>'<img src=. onerror=alert(1)>'),);
$id = $_GET['id'] ?? "1";
$user = $users[$id];
?>
~略~
<div id="app">
<my-conponent>Hello world!</my-conponent>
<p><a href="/xss4.php?id=2">demo</a></p>
</div>
<script>
const props = JSON.parse(
'{"domProps": { "innerHTML": "<?=$user["user_name"] ?> さん" }}')
let myConponent = Vue.component('my-conponent', {
render: function (createElement) {
return createElement('h1', props)
}
})
new Vue({
el: '#app',
components: {
'my-conponent': myConponent
}
})
</script>
40
- 41. domProps
初期表示だとこんな感じです。
<?php
$users = array( "1" => array("user_name"=>"default"),
"2" => array("user_name"=>'<img src=. onerror=alert(1)>'),);
$id = $_GET['id'] ?? "1";
$user = $users[$id];
?>
~略~
<div id="app">
<my-conponent>defaultさん</my-conponent>
<p><a href="/xss4.php?id=2">demo</a></p>
</div>
<script>
const props = JSON.parse(
'{"domProps": { "innerHTML": "<?=$user["user_name"] ?> さん" }}')
let myConponent = Vue.component('my-conponent', {
render: function (createElement) {
return createElement('h1', props)
}
})
new Vue({
el: '#app',
components: {
'my-conponent': myConponent
}
})
</script>
41
- 42. domProps
リンクをクリックします。
<?php
$users = array( "1" => array("user_name"=>"default"),
"2" => array("user_name"=>'<img src=. onerror=alert(1)>'),);
$id = $_GET['id'] ?? "1";
$user = $users[$id];
?>
~略~
<div id="app">
<my-conponent>defaultさん</my-conponent>
<p><a href="/xss4.php?id=2">demo</a></p>
</div>
<script>
const props = JSON.parse(
'{"domProps": { "innerHTML": "<?=$user["user_name"] ?> さん" }}')
let myConponent = Vue.component('my-conponent', {
render: function (createElement) {
return createElement('h1', props)
}
})
new Vue({
el: '#app',
components: {
'my-conponent': myConponent
}
})
</script>
42
- 43. domProps
リンクをclickするとこんな感じで出力されて、アラートが発動します。
<?php
$users = array( "1" => array("user_name"=>"default"),
"2" => array("user_name"=>'<img src=. onerror=alert(1)>'),);
$id = $_GET['id'] ?? "1";
$user = $users[$id];
?>
~略~
<div id="app">
<my-conponent><img src=. onerror=alert(1)>さん</my-conponent>
<p><a href="/xss4.php?id=2">demo</a></p>
</div>
<script>
const props = JSON.parse(
'{"domProps": { "innerHTML": "<?=$user["user_name"] ?> さん" }}')
let myConponent = Vue.component('my-conponent', {
render: function (createElement) {
return createElement('h1', props)
}
})
new Vue({
el: '#app',
components: {
'my-conponent': myConponent
}
})
</script>
43
- 45. Vue.js に XSS が入るパターン
v-pre
v-bind
SSR(Mustache)
domProps
compile
45
- 47. compile
ここでXSSが発動します。
<?php
$users = array(
"1" => array("user_name"=>"default"),
"2" => array("user_name"=>'<img src=. onerror=alert(1)>'),
);
$id = $_GET['id'] ?? "1";
$user = $users[$id];
?>
~略~
<div id="app"></div>
<script>
var res = Vue.compile(
'<div><?=$user["user_name"]; ?> さんのプロフィール<br><a
href="/xss5.php?id=2">demo</a></div>’)
new Vue({
el: '#app’,
render: res.render,
})
</script>
47
- 48. compile
初期表示だとこんな感じです。
<?php
$users = array(
"1" => array("user_name"=>"default"),
"2" => array("user_name"=>'<img src=. onerror=alert(1)>'),
);
$id = $_GET['id'] ?? "1";
$user = $users[$id];
?>
~略~
<div id="app">
<div>
default さんのプロフィール<br>
<a href="/xss5.php?id=2">demo</a>
</div>
</div>
<script>
var res = Vue.compile(
'<div><?=$user["user_name"]; ?> さんのプロフィール<br><a
href="/xss5.php?id=2">demo</a></div>’)
new Vue({
el: '#app’,
render: res.render,
})
</script>
48
- 49. compile
リンクをclickします。
<?php
$users = array(
"1" => array("user_name"=>"default"),
"2" => array("user_name"=>'<img src=. onerror=alert(1)>'),
);
$id = $_GET['id'] ?? "1";
$user = $users[$id];
?>
~略~
<div id="app">
<div>
default さんのプロフィール<br>
<a href="/xss5.php?id=2">demo</a>
</div>
</div>
<script>
var res = Vue.compile(
'<div><?=$user["user_name"]; ?> さんのプロフィール<br><a
href="/xss5.php?id=2">demo</a></div>’)
new Vue({
el: '#app’,
render: res.render,
})
</script>
49
- 50. compile
リンクをclickするとこんな感じで出力されて、アラートが発動します。
<?php
$users = array(
"1" => array("user_name"=>"default"),
"2" => array("user_name"=>'<img src=. onerror=alert(1)>'),
);
$id = $_GET['id'] ?? "1";
$user = $users[$id];
?>
~略~
<div id="app">
<div>
<img src=. onerror=alert(1)> さんのプロフィール<br>
<a href="/xss5.php?id=2">demo</a>
</div>
</div>
<script>
var res = Vue.compile(
'<div><?=$user["user_name"]; ?> さんのプロフィール<br><a
href="/xss5.php?id=2">demo</a></div>’)
new Vue({
el: '#app’,
render: res.render,
})
</script>
50
- 55. 参考URL
Vue.js
https://jp.vuejs.org/v2/guide/index.html
https://jp.vuejs.org/v2/guide/syntax.html
VueをSSRに乗せると容易にXSSを生み出す場合がある件について
https://qiita.com/alfa/items/b0e807ae040fc8f61d20
最近のJavaScriptフレームワークでのXSS | "><s>はい</s>
https://blog.ssrf.in/post/modern-javascript-framework-xss/
Vue.js で XSS を作り込まないために気を付けること - SSTエンジニアブログ
https://techblog.securesky-tech.com/entry/2018/08/01/110000
XSS in the era of *.js - JS ライブラリ時代の XSS (ゼロから始めるセキュリティ入門勉強会 #15) - Speaker
Deck
https://speakerdeck.com/lmt_swallow/xss-in-the-era-of-star-dot-js-js-raiburarishi-dai-false-xss-
zerokarashi-merusekiyuriteiru-men-mian-qiang-hui-number-15
55