koukiblog

たぶんweb系の話題

vueのXSSの件について考えてみた

↓の記事のことです。 qiita.com

vue管理のテンプレートに、UGC(User Generated Content)を含めない。 というのが原則だとは思うのだけど、既にRailsレンダリングしてるviewのイベント周りだけvueに任せたい、など、vueを薄く使っている場合はサーバサイドのテンプレートエンジンでvueのテンプレートを出力することは結構あるんじゃないでしょうか。

vue側の反応

fix #4223, add interpolation config. by alfa-jpn · Pull Request #6203 · vuejs/vue · GitHub

However, there is no silver bullet for server side vue template, especially when users want to mix user generated content with programmer’s template. IMHO, Vue’s users can and should think over how to separate UGC and template. On the other hand, Vue’s API is already large enough. Vue.config.interpolation can be easily replaced by v-pre that already exists. Users can even provide non-matching regex to mock this pull request. While we thank your contribution, we might still keep our API surface not too large. (Vue’s API is already not as small as it used to be). For more reasoning, please see #6004 (comment).

ユーザー側でなんとかしてほしいということで、まぁそうだねーいう感じ。

vueには、v-preという機能が既にあり、v-pre配下はvueのコンパイルがスキップされるのでそれを使えばよいということです。 https://jp.vuejs.org/v2/api/index.html#v-pre

{{ }} をサーバー側で防ぐ

ぱっと思いついたのは、サーバ側でhtml escapeするときにvueのマスタッシュ構文にも対応するという方法です。 ただ、HTMLエスケープは、Railsのように自動でHTMLエスケープしている環境ではパフォーマンス上重要な箇所( Escape Velocity · GitHub )であり、そこに追加するのはあまりよくない気がしました。

なので、Railsでやるとすれば↓のようにマスタッシュ構文を削除するなりスペース挟むなりするhelper作って明示的に防ぐことになるのかなーと思うのですが

<div>
  <%= v_safe(@user.name) %>
</div>

その場合

<div v-pre>
  <%= @user.name %>
</div>

とほぼ同じだしv-pre使った方が確実でvueのコンパイルもスキップできてパフォーマンス上も有利だし、わざわざ自前でhelper書く意味はなさそう。

結論

vueのテンプレートと、HTMLは違うコンテキストを持っている、ということを意識してやっていくしかなさそう。仕組みで防げなくて微妙な感じもしますが、PRへのコメントにもあった通り銀の弾丸はないってことなんでしょう。

interpolation無効化するのは超単純なアプリの場合はそれでいいかもしれないけど、ある程度複雑なアプリになると初期表示後のイベントとかどこかで必要になるんじゃないかなと思いました。