讀者 Kg 分享,我愛用的 Vue 3.0 輕前端寫法若遭遇資安政策要求禁用 CSP script-src 'unsafe-eval' 將會失效。登楞!!!

研究了一下,Vue 超方便的 template 寫法 template: '<div>{{ message }}</div>',底層需要 eval 函式才能運作:

const app = Vue.createApp({
    data() {
      return {
        message: 'Hello Vue!'
      }
    },
    template: '<div>{{ message }}</div>'
});

因此,若網站或網頁啟用 CSP script-src 但沒開放 'unsafe-eval',將導致 Vue 3.0 噴出錯誤:「Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self'".」,用以下 HTML 可重現問題:

<!DOCTYPE html>
<html>
  <head>
    <title>My Vue App</title>
    <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
  </head>
  <body>
    <div id="app"></div>
    <script src="vue.global.prod.min.js"></script>
    <script src="app.js"></script>
  </body>
</html>

執行後看不到 Hello Vue! 且出現錯誤:

要解決這類問題,~~一概建議先解決資安人員(大誤)~~正統做法是回歸預先編譯,搬 webpack 出來並加上編譯程序,但如此形同棄守輕前端。

我找到第二條路,用 render 取代 template,無奈改用 render() 的寫法超級囉嗦,Vue 的輕巧易用特性盡失,難以視為替代方案。但我還是試寫一段體驗:
註:h() 的用法可參考官方文件,概念接近 .NET System.Xml.Linq 宣告 XElement 的玩法,不難理解。

let h = Vue.h;
const app = Vue.createApp({
  data() {
    return {
      message: 'Hello Vue!'
    }
  },
  render() {
    return h('div', 
      { 'id': 'demo', 'class': 'my-css'}, 
      [
        'Hello, Vue!',
        h('p', 'simple text only paragraph'),
        h('p', { 'class': 'p-css' }, [
          h('span', 'Nested Span')
        ])
      ]
    );
  }
})

app.mount('#app')

將 Vue 程式庫換成 vue.runtime.global.prod.min.js,搭配 render() 版本,即可在 CSP 嚴格限制下忍辱偷生:

但是,寫慣 template 字串式宣告後應該沒人能接受這種折磨,更甭提把所有 template 語法改成這副德行。

使用 JSX 語法配合 babel-plugin-jsx 是另一個解決方向,JAX 會像這樣:

// app.jsx
const app = Vue.createApp({
    data() {
      return {
        message: 'Hello Vue!'
      }
    },
    render() {
      <div>{{ message }}</div>
    }
});
app.mount('#app');

簡潔度與 template 相去不遠,但缺點是 jsx 也需要事前編譯,且需要學習 JSX 語法,與輕前端的理念不符。

結論:想在 CSP 不允許 unsafe-eval 的環境使用 Vue 3 輕前端寫法,目前無解,想突圍只能棄守改用預先編譯。

傳統 JavaScript 程式依賴 eval() 寫法的場合蠻遍的,全面禁止會血流成河似乎也在預期之內,衝擊跟全面禁止 HTTP 一律用 HTTPS 差不多,故猜想短期還不致全面強制推行,但心理可能要先有底了。

【參考資料】

Survey of CSP 'unsafe-eval' issue on Vue.js and possible solution.


Comments

# by GM

使用importmap載入 vue3不知可不可以避掉unsafe- eval

# by Lik

坦白講,資安我第一個想到的是網上銀行 我查了台灣幾個銀行,也沒有辦法做到 CSP 所謂的禁止eval , 例如 https://www.bot.com.tw/tw/personal-banking, 你去https://csp-evaluator.withgoogle.com/ 查查看,它也是要用到'unsafe-eval'。那我們也不急啦。。。

# by Jeffrey

to Lik, 禁用 eval 衝擊超大的,相對它造成的風險,禁用不太符合效益吧。

Post a comment