Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Vue.js で XSS

755 views

Published on

Vue.jsでXSSが発生するケースについて調べてみました。

Published in: Internet
  • Be the first to comment

Vue.js で XSS

  1. 1. Vue.jsでXSS 2018/08/29 沖縄・宜野湾エンジニア勉強会#2 桃原 裕太
  2. 2. はじめに 2
  3. 3. はじめに Vue.jsのXSSについて調べました きっかけ  Vue.jsのXSSについて、記事があがってたので自分でも試してみました。  VueをSSRに乗せると容易にXSSを生み出す場合がある件について  https://qiita.com/alfa/items/b0e807ae040fc8f61d20 3
  4. 4. 自己紹介 桃原 裕太 株式会社シーエー・アドバンス 技術統括本部 Webアプリケーション脆弱性診断に携わって約6年 月一でセキュリティもくもく勉強会を開催 4
  5. 5. Vue.js とは? Vue.js について軽く 説明していきたいと思います 5
  6. 6. Vue.js とは? “Vue (発音は / v j u ː / 、 view と同様)は ユーザーインターフェイスを構築するための プログレッシブフレームワークです。他の一 枚板(モノリシック: monolithic)なフレーム ワークとは異なり、Vue は少しずつ適用して いけるように設計されています。” - 公式サイト(jp.vuejs.org)から引用 6
  7. 7. Vue.js とは? 触ってみた印象(私まだ入門レベルですが…) JavaScriptのフレームワーク 下記が便利 データバインディング 独自ディレクティブ トランジション 一度作ったリソースの再利用 7
  8. 8. XSS とは? XSS について軽く 説明していきたいと思います 8
  9. 9. XSS とは? クロスサイト・スクリプティングの略で、 すごく有名な脆弱性です 脆弱性 システム上の悪用可能な不具合のこと XSSはユーザー入力値の出力時に、タグ文 字が出力されたりするバグです。 9
  10. 10. XSS とは? XSSの何が問題? 画面の一時的な改ざんによる フィッシング詐欺などで悪用される 下記情報が抜かれることも cookieのセッションID localStorageに格納した値 10
  11. 11. XSS とは? 3パターンあります。 反射型 入力した次のページで発生するXSS 蓄積型 DB等に登録後、別ページで発生するXSS DOMベース型 DOM構築時に発生するXSS 11
  12. 12. XSS とは? 反射型 入力した次のページで発生するXSS 下記URLにアクセスした場合のエスケープ 漏れ、等 http://localhost:8000/?search=<script>alert(1);<script> 12
  13. 13. XSS とは?  蓄積型 持続型とも言われます DB等に登録後、別ページで発生するXSS ユーザAが名前を「<script>alert(1);<script>」で登 録していて、プロフィール画面で適切にエスケープさ れていない場合 ユーザBがユーザAのプロフィールを閲覧するとアラー トが発動 ユーザCがユーザAのプロフィールを閲覧するとアラー トが発動 13
  14. 14. XSS とは? DOMベース型 DOM構築時に発生するXSS ログイン失敗時に下記のようなURLでエラー メッセージを表示していて、適切にエスケー プされていない場合 http://localhost:8000/#msg=IDかPWが間違っています 下記URLにアクセスするとアラートが発動 http://localhost:8000/#msg=<script>alert(1);<script> 14
  15. 15. Vue.js に XSS が入る パターン 本題です 15
  16. 16. Vue.js に XSS が入るパターン v-pre v-bind SSR(Mustache) domProps compile 16
  17. 17. Vue.js に XSS が入るパターン v-pre v-bind SSR(Mustache) domProps compile 17
  18. 18. v-html ソースコードベースで解説していきます。 18
  19. 19. v-html ここでXSSが発生します。 <div id="app"> <p><span v-html="msg"></span></p> <input v-model="msg"> </div> <script> new Vue({ el: '#app‘, data: { msg: '' } }) </script> 19
  20. 20. v-html 画面上でテキストボックスに <img src=. onerror=“alert(1)”> を入力します。 <div id="app"> <p><span v-html="msg"></span></p> <input v-model="msg"> </div> <script> new Vue({ el: '#app', data: { msg: '' } }) </script> 20 <img src=. onerror="alert(1)">
  21. 21. v-html scriptタグ内のdata[msg]に <img src=. onerror=“alert(1)”> が反映されます。 <div id="app"> <p><span v-html="msg"></span></p> <input v-model="msg"> </div> <script> new Vue({ el: '#app', data: { msg: '<img src=. onerror="alert(1)">' } }) </script> 21 <img src=. onerror="alert(1)">
  22. 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)">
  23. 23. v-html  対策  ユーザーの入力値を出力する箇所では Mustache構文を使いましょう  こういうの → {{ msg }}  補足  公式にもv-htmlについて記載があります  “XSS 脆弱性を容易に引き起こすので、ウェブサ イトで動的に任意のHTMLを描画することは、非 常に危険です。信頼できるコンテンツにだけ HTML 展開を利用してください。ユーザーから提 供されたコンテンツに対しては決して使用しては いけません。” 23
  24. 24. v-pre v-bind SSR(Mustache) domProps compile 24 Vue.js に XSS が入るパターン
  25. 25. v-bind ソースコードベースで解説していきます。 25
  26. 26. v-bind v-bind:href で解説します。aタグでXSSが発生します。 <div id="app"> <a v-bind:href="url">Demo</a><br> <input v-model="url"> </div> <script> new Vue({ el: '#app', data: { msg: 'test' } }) </script> 26
  27. 27. v-bind v-htmlと同様にテキストボックスに文字を入力します。 <div id="app"> <a v-bind:href="url">Demo</a><br> <input v-model="url"> </div> <script> new Vue({ el: '#app', data: { msg: '' } }) </script> 27 javascript:alert(1)
  28. 28. v-bind scriptタグ内のdata[msg]に javascript:alert(1) が反映されま す。 <div id="app"> <a v-bind:href="url">Demo</a><br> <input v-model="url"> </div> <script> new Vue({ el: '#app', data: { msg: 'javascript:alert(1)' } }) </script> 28 javascript:alert(1)
  29. 29. v-bind aタグ内のhrefに javascript:alert(1) が反映されます。 反映後にリンクをclickするとアラートが発動します。 <div id="app"> <a v-bind:href="url" href="javascript:alert(1)">Demo</a><br> <input v-model="url"> </div> <script> new Vue({ el: '#app', data: { msg: 'javascript:alert(1)' } }) </script> 29 javascript:alert(1)
  30. 30. v-bind  対策  ユーザーの入力値を出力する箇所ではv-bindを使わないように します  どうしても入力値に応じた出力が必要な場合は、算出プロパ ティ(computed)で間接的に値を渡すのがよさそうかなと思っ ています。こういうことやってるよ!等、詳しい方いたら教え てください。  補足  v-bind:href 以外にも、下記で似たような動作を確認しました  v-bind:onmouseover  v-bind:onfocus  v-bind:onblur  v-bind:onerror  onclick等、他にもあると思います 30
  31. 31. Vue.js に XSS が入るパターン v-pre v-bind SSR(Mustache) domProps compile 31
  32. 32. SSR (Mustache) ソースコードベースで解説していきます。 32
  33. 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. 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. 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
  36. 36. SSR (Mustache) リンクをclickするとこんな感じで出力されて、アラートが発動します。 <?php $name = $_GET['name'] ?? "default"; ?> ~略~ <div id="app"> <p> ようこそ {{ alert(1) }} さん </p> <p><a href="?name={{%20alert(1)%20}}">demo</a></p> </div> <script> new Vue({ el: '#app', data: { msg: 'test' } }) </script> 36
  37. 37. SSR(Mustache)  対策  ユーザーにMustache構文を使わせないようにしま しょう。  サーバーサイドレンダリングで、ユーザーの入力 値を出力する箇所では通常のHTMLエスケープを 行った上で v-pre を使います。  補足  Mustache構文の中ではJavaScriptが直接かけ るみたいです。  こういうの → {{ alert(1) }} 37
  38. 38. Vue.js に XSS が入るパターン v-pre v-bind SSR(Mustache) domProps compile 38
  39. 39. domProps ソースコードベースで解説していきます。 39
  40. 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. 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. 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. 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
  44. 44. domProps  対策  ユーザーの入力値を出力する箇所ではdomPropsの innerHtmlを使わないようにします。  補足  脆弱性の自然な流れが見つからないので詳しい 方いたら教えてください… 44
  45. 45. Vue.js に XSS が入るパターン v-pre v-bind SSR(Mustache) domProps compile 45
  46. 46. compile ソースコードベースで解説していきます。 46
  47. 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. 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. 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. 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
  51. 51. compile  対策  ユーザーの入力値を出力する箇所では Vue.compileを使わないようにします  補足  Mustache記法が使えるので、HTMLのエスケー プだけだと不十分な可能性があります。  脆弱性の自然な流れが見つからないので詳しい 方いたら教えてください… 51
  52. 52. 終わりに まとめます 52
  53. 53. 終わりに Vue.js で XSS が入るパターンについて学 びました。 サイトにXSSが入らないように気をつけま しょう。 53
  54. 54. 終わりに 紹介したケース以外でXSSの発生条件を 知ってる方がいたら教えてくださいm(_ _)m スライドで紹介したものは簡易版ですが、 検証したソースも公開しています。 https://github.com/toubaru/vue-xss 54
  55. 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

×