escapeInject

环境:Node.js

escapeInject 字符串模板标签净化 HTML(以防止所谓的 XSS 注入 安全漏洞)。

它通常用在 renderer/_default.page.server.js 中定义的 render() hook 中。

// renderer/_default.page.server.js
// Environment: Node.js

export { render }

import { escapeInject, dangerouslySkipEscape } from 'vite-plugin-ssr'

async function render() {
	const title = 'Hello<script src="https://devil.org/evil-code"></script>'

	// 由于 `escapeInject` 净化了 `title`,这个 HTML 是安全的
	return escapeInject`<!DOCTYPE html>
    <html>
      <head>
        <title>${title}</title>
      </head>
      <body>
        <!-- ... ->
      </body>
    </html>`
}

所有字符串,例如 上面的 title 会自动净化(从技术上讲:HTML 转义) 这样我们就可以安全地包含不受信任的字符串 例如用户生成的文本。

dangerouslySkipEscape(str) 函数按原样注入字符串 str 而不经过净化。 我们应该非常谨慎地使用 dangerouslySkipEscape(), 并且仅用于已经净化过的 HTML 字符串。 我们通常使用 dangerouslySkipEscape() 来包含由 UI 框架(React/Vue/...)生成的 HTML,因为这些已被净化。 如果我们发现自己在其他情况下使用 dangerouslySkipEscape(),我们应该格外小心,因为我们会遇到造成安全漏洞的风险。

HTML Fragments

我们可以从几个 HTML fragments 组装进 HTML 文档 例如,如果我们希望某些 HTML 仅包含在某些页面中:

// _default.page.server.js
// Environment: Node.js

import { escapeInject, dangerouslySkipEscape } from 'vite-plugin-ssr'
import { renderToHtml } from 'some-ui-framework'

export { render }

async function render(pageContext) {
	const description = pageContext.exports.description
	const descriptionTag = !description
		? ''
		: // 我们对 HTML fragment 使用 `escapeInject`
		  escapeInject`<meta name="description" content="${description}">`

	// 我们再次对整个 HTML 使用 `escapeInject`
	return escapeInject`<html>
    <head>
      ${descriptionTag}
    </head>
    <body>
      <div id="root">
        ${dangerouslySkipEscape(await renderToHtml(pageContext.Page))}
      </div>
    </body>
  </html>`
}

pageContext.exports.description自定义 Export

Example: