背景:公司的项目统一需要做Xss防护,Vue3、Vue2、React 的项目都需要做,这篇文章先写如何在 React里面做的,Vue 系列的后续补充到掘金
结论 :我们知道 React 的 dangerouslySetInnerHTML 是 React 为浏览器 DOM 提供 innerHTML 的替换方案。 如果项目里面 dangerouslySetInnerHTML 比较多的话,又懒得一个一个改,可以使用 babel-plugin-react-injectxsscode 插件,在编译阶段可以自动注入 dangerouslySetInnerHTML.__html 所需要的 XSS 过滤方法。(实际的 Xss 函数还是需要自定义的, 只是babel-plugin-react-injectxsscode 帮你找到需要注入的地方,并且完成注入)
介绍:babel-plugin-react-injectxsscode 是一个 babel 插件,接入该插件对原先的业务没有侵入,当识别到 jsx 文件里面的 dangerouslySetInnerHTML 属性之后,自动注入 在 babel.config.js 配置的 packageName 的 injectFnName函数包装 dangerouslySetInnerHTML属性值(其实是一个高阶函数,类似 AOP 的概念,对dangerouslySetInnerHTML属性值 进行增强,只不过这里的增强是 XSS 增强)
如何使用:
json
// 使用 npm 安装 babel-plugin-react-injectxsscode 插件
npm i babel-plugin-react-injectxsscode`
js
//babel.config.js 或者 .babelrc
const babelPluginReactInjectXssCode = require('babel-plugin-react-injectxsscode')
module.exports = {
...
plugins: [
...
// [packageName] 是 编译之后 导入的 npm 包的名字
// [composeXssFn] 是 packageName这个 npm包导出的函数
// 从 [packageName] 导出 [composeXssFn] 函数给 dangerouslySetInnerHTML 使用
[babelPluginReactInjectXssCode, { packageName: 'utils', injectFnName: 'composeXssFn' }]
]
}
效果如下所示:
对业务代码没有任何入侵
使用插件效果(webpack 编译 jsx 的效果图)
使用插件效果(单个 jsx 文件编译之后的效果图)
原理分析:
- 识别到jsx文件
- 找到jsx文件到 dangerouslySetInnerHTML对应的__html属性对应的 value
- 查看改jsx文件有没有 导入过 [packageName] 这个包,没有倒入过的话直接倒入(新增一个 import 节点)。如果导入过的话,需要查看 [injectFnName] 函数有没有倒入过,如果[injectFnName] 函数导入过的话,无需任何处理。没有没有倒入,在AST里面导入该函数。
- 详细看源码注释 (github 源码插件链接)