@wuipkg/security-review
v0.7.5
Published
面向构建前与 CI 阶段的安全审查工具包,提供 CLI、Vite、webpack 与 ESLint 子入口。旨在从代码规范、静态资源暴露、第三方依赖风险等多维度阻断潜在安全隐患。
Downloads
280
Readme
@wuipkg/security-review
面向构建前与 CI 阶段的安全审查工具包,提供 CLI、Vite、webpack 与 ESLint 子入口。旨在从代码规范、静态资源暴露、第三方依赖风险等多维度阻断潜在安全隐患。
核心特性
- 多环节覆盖: 支持在
pre-commit(Git 暂存区),build(构建流程),post-build(构建产物检查) 及ci环境无缝运行。 - 全链路适配: 提供 CLI 原生命令执行,同时内置无缝衔接 Vite 和 Webpack 的构建插件。
- 框架覆盖: 源码扫描同时覆盖原生 JS/TS、Vue SFC 与 React JSX/TSX。
- 丰富的审查规则: 内置 26 种前沿前端与 Node 服务安全审查规则,涵盖硬编码密钥、敏感凭证泄露、DOM XSS、表单劫持、动态导入、正则安全、构建产物策略检查等。
- 灵活动态的配置: 支持
wui-security.config.ts以及基于辅助函数的系统环境变量动态配置,快速适应复杂工程与自动化流水线。 - 抑制机制: 支持
security-ignore注释(JS/TS/JSX/TSX 行注释与 Vue 模板 HTML 注释),在人工审核后抑制特定发现。 - 自定义检测: 通过
detect回调函数扩展非标准 HTTP 客户端的凭证检测。
安装
pnpm add @wuipkg/security-review -D规则清单
本工具内置以下 26 条安全审查规则,分为三大类:
源码规则 (Source Rules)
运行在 pre-commit、build、ci 阶段,对源代码文件进行 AST 静态分析。
| 规则名 | 默认等级 | 描述 |
| ---------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| hardcoded-secret | error | 检测源码中的明文 AccessKey、私钥、口令与内网地址。支持 AWS、GitHub、GitLab、Stripe、OpenAI、Google、npm Token 等 10+ 种密钥格式。 |
| dangerous-dom-api | error | 检测 v-html、React dangerouslySetInnerHTML、innerHTML、outerHTML、document.write、eval、new Function()、setTimeout/setInterval 字符串参数。 |
| postmessage-origin | error | 要求 window.addEventListener('message', ...) 处理器首行校验 event.origin。 |
| unsafe-redirect | error | 基于 AST 精确匹配检测直接基于 URL 参数的 location.href、location.assign/replace、Vue Router 跳转,以及 React Router 常见导航语义(如 useNavigate() 返回的 navigate(...)、<Navigate to={...} />)。支持 safeRedirectFunctions 安全函数白名单和 checkRouteParams 配置。 |
| sensitive-storage | error | 检测 localStorage/sessionStorage.setItem 明文存储 token、idCard 等敏感字段。 |
| unsafe-url-scheme | error | 拦截 href/src/action 及 window.open 中的 javascript:、data:、vbscript: 协议。 |
| deprecated-crypto | error | 检测前端使用 CryptoJS.MD5/SHA1 等弱密码学算法。 |
| postmessage-wildcard | error | 拦截 postMessage 使用通配符 '*' 作为 origin。 |
| unsafe-deep-clone | warn | 检测未过滤 __proto__/constructor/prototype 的深拷贝实现。 |
| unsafe-target-blank | warn | 检测 target="_blank" 缺失 rel="noopener"(Vue 模板、JSX/TSX、window.open)。 |
| unsafe-regex | warn | 基于 AST 分析容易引发 ReDoS 攻击的正则表达式。 |
| client-cookie-security | warn | 检测 document.cookie 及 Cookie 库 .set() 缺失 Secure 或 SameSite 属性。 |
| console-log-leak | warn | 检测 console.log/warn/error 等输出中包含敏感变量名(如 token、password、secret)的参数。 |
| insecure-fetch-credentials | warn | 检测 fetch({ credentials: 'include' })、axios.create({ withCredentials: true })、xhr.withCredentials = true 等跨域凭证发送。 |
| form-action-hijack | warn | 检测表单 action 属性指向外部域(静态 HTML、Vue :action/v-bind:action 绑定、JSX/TSX),并对 Vue / React 的动态绑定表达式给出显式风险提示。 |
| iframe-allow-permissions | warn | 检测 iframe allow 是否显式授予摄像头、麦克风、定位等敏感权限,并对无法静态确认的动态绑定给出风险提示。原生 HTML 文件需显式把 .html/.htm 加入 sourceExtensions 后才会参与源码扫描。 |
| unsafe-dynamic-import | warn | 检测动态 import() 参数为非字面量的情况,防止 SSR/Electron 场景下任意模块加载。 |
产物规则 (Output Rules)
运行在 post-build、build、ci 阶段,对构建产物和配置文件进行检查。
其中 HTML advisory 规则(csp-policy、subresource-integrity、referrer-policy)遵循以下约定:
- 配置为
.html/.htm的文件时,只检查outDirs下的构建产物,不检查源码模板。 build阶段不会对 HTML advisory 文件做判定,因为构建期动态注入尚未完成;请使用post-build或ci获取最终结果。- 配置为
nginx.conf之类的非 HTML 文件时,仍然按项目根目录下的配置文件读取。 subresource-integrity可通过ignoredDomains跳过指定外部域名,域名按 hostname 精确匹配。
| 规则名 | 默认等级 | 描述 |
| ------------------------ | -------- | ---------------------------------------------------------------------------------- |
| source-map-leak | error | 检查发布产物目录是否残留 .map 文件或 sourceMappingURL 注释。 |
| env-file-exposure | error | 扫描构建产物目录是否包含 .env 文件。 |
| git-directory-exposure | error | 检测构建产物目录是否包含 .git 目录,防止源码泄露。 |
| csp-policy | warn | 检测入口 HTML 是否存在 Content-Security-Policy 配置。 |
| subresource-integrity | warn | 检测外部 script/link 标签是否包含 integrity 属性(SRI)。 |
| referrer-policy | warn | 检测是否配置 Referrer-Policy: strict-origin-when-cross-origin。 |
依赖规则 (Dependency Rules)
| 规则名 | 默认等级 | 描述 |
| -------------------------- | -------- | ------------------------------------------------------------- |
| dependency-audit | error | 执行 npm audit / pnpm audit 检查已知漏洞。 |
| lockfile-registry | error | 校验 .npmrc 及 lockfile 中的 npm 源域名是否在可信白名单内。 |
| prototype-pollution-deps | error | 检测高风险原型链污染依赖。 |
全局配置 (wui-security.config.ts)
在项目根目录创建 wui-security.config.ts,这里将作为所有工具链检查逻辑的真相来源 (Single Source of Truth):
import { defineSecurityConfig } from '@wuipkg/security-review'
export default defineSecurityConfig({
// 1. 指定 lockfile 与 .npmrc 允许出现的 npm 源域名
allowedRegistryDomains: ['registry.npmjs.org', 'npm.company.com'],
// 2. 指定执行 npm / pnpm audit 时使用的审计源
audit: {
registry: 'https://registry.npmjs.org'
},
// 3. 检查特定文件中是否忘记配置安全 Meta 标签或 SRI 属性
// - HTML 文件会映射到 outDirs 下的构建产物,例如 dist/index.html
// - 非 HTML 文件(如 nginx.conf)则直接按项目根目录读取
advisoryFiles: {
'csp-policy': ['index.html'],
'subresource-integrity': ['index.html'],
'referrer-policy': ['index.html']
},
// 4. 构建产物目录(用于 source-map-leak / env-file-exposure / git-directory-exposure
// 以及 HTML advisory 规则定位最终产物文件)
outDirs: ['dist', 'build'],
// 5. 豁免的安全路由/持久化存储函数名单
safeNavigationFunctions: ['safeNavigate', 'appNavigate', 'router.push'],
safeStorageFunctions: ['encryptedStorage'],
// 6. 扫描的目标源代码扩展名及需要过滤忽略的路径
sourceExtensions: ['.js', '.jsx', '.ts', '.tsx', '.vue'],
ignore: ['node_modules', '.git', 'dist', '.turbo'],
// 7. Trufflehog (高价值密钥扫描器) 集成支持
trufflehog: {
enabled: false,
command: 'trufflehog'
},
// 8. 导出离线 HTML 分析报告
htmlReport: {
enabled: false,
outputFile: 'security-report.html',
exposeScannedFiles: false
// template: './custom-template.html'
},
// 9. 自定义各个规则等级与参数配置 (off | warn | error)
rules: {
'hardcoded-secret': 'error',
'dependency-audit': 'error',
'unsafe-deep-clone': 'warn',
'sensitive-storage': {
level: 'error',
options: { sensitiveKeys: ['token', 'idCard', 'passport'] }
},
'source-map-leak': {
level: 'error',
options: { outDirs: ['dist'] }
},
'subresource-integrity': {
level: 'warn',
options: {
files: ['index.html'],
ignoredDomains: ['www.googletagmanager.com']
}
},
// 新增规则配置示例
'console-log-leak': {
level: 'warn',
options: {
sensitiveIdentifiers: [
'token',
'password',
'secret',
'apiKey',
'credential'
]
}
},
'insecure-fetch-credentials': {
level: 'warn',
options: {
httpClientNames: ['axios', 'http', 'request', 'api', 'service']
}
},
'form-action-hijack': {
level: 'warn',
options: {
allowedDomains: ['payment.company.com']
}
},
'iframe-allow-permissions': {
level: 'warn',
options: {
sensitivePermissions: [
'camera',
'microphone',
'geolocation',
'payment'
]
}
},
'git-directory-exposure': 'error',
'unsafe-dynamic-import': 'warn',
'unsafe-redirect': {
level: 'error',
options: {
// 声明项目中的安全校验函数,被这些函数包裹的跳转不会告警
safeRedirectFunctions: ['validateUrl', 'sanitizeRedirect'],
// 默认不检查 route.params(受路由表约束),设为 true 启用检查
checkRouteParams: false
}
}
}
})自定义检测回调
对于非标准 HTTP 客户端(如公司内部封装的 myHttp 库),可通过 detect 回调函数扩展 insecure-fetch-credentials 规则的检测范围:
import type { CredentialDetectFn } from '@wuipkg/security-review'
import { defineSecurityConfig } from '@wuipkg/security-review'
const detectInsecureCredentials: CredentialDetectFn = (ctx) => {
// 检测 myHttp.post(url, { sendCookies: true })
if (
ctx.callee === 'myHttp' &&
ctx.property === 'sendCookies' &&
ctx.value === true
) {
return true
}
return false
}
export default defineSecurityConfig({
rules: {
'insecure-fetch-credentials': {
level: 'warn',
options: {
detect: detectInsecureCredentials
}
}
}
})detect 回调的上下文参数 (CredentialDetectContext):
| 字段 | 类型 | 描述 |
| ---------- | --------------------------- | ----------------------------------------------------------- |
| callee | string | 调用者变量名,如 'myHttp'、'customFetch' |
| method | string \| null | 方法名(成员调用时),如 'post'。直接调用时为 null |
| property | string | 配置对象中当前属性名 |
| value | boolean \| string \| null | 属性值(仅 BooleanLiteral 或 StringLiteral,其余为 null) |
行内抑制 (security-ignore)
在人工确认安全后,可使用行内注释抑制特定规则的报告。注释需放在目标代码的上一行:
JS/TS 文件
// security-ignore insecure-fetch-credentials
axios.create({ withCredentials: true }) // 已确认仅对同源 API 生效
// security-ignore console-log-leak
console.log(token) // 仅开发环境使用,生产构建已配置 drop_consoleReact / JSX / TSX
const html = '<p>controlled</p>'
// security-ignore dangerous-dom-api 已确认仅受控富文本渲染
export const Preview = () => <div dangerouslySetInnerHTML={{ __html: html }} />Vue 模板 (<template>)
<!-- security-ignore form-action-hijack -->
<form :action="paymentUrl">
<input type="text" name="card" />
</form>行为规则
- 注释仅抑制紧邻的下一行的匹配发现,不会跨行生效
- 规则名必须精确匹配,
// security-ignore unsafe-regex不会抑制console-log-leak - 无行号信息的 finding(如
source-map-leak)不可被抑制
报告展示
抑制的发现不会被静默丢弃,而是:
- 终端报告: 在 summary 下方显示 "已忽略 N 条",并在明细区列出每条被抑制的 finding
- HTML 报告: 在底部以 "Suppressed Findings" 区块展示,并列出每条被抑制的 finding 与忽略理由
- API 返回: 通过
report.suppressedFindings数组获取,report.summary.suppressed记录条数
环境变量与动态配置
在 Node.js 运行时,wui-security.config.ts 会被动态加载解析。你可以直接通过 process.env 配合辅助函数灵活读取字符串、布尔及数组类型变量。
// wui-security.config.ts
import { defineSecurityConfig } from '@wuipkg/security-review'
/**
* 辅助函数:将以逗号分隔的字符串转换为去重、无空值的纯净数组
*/
const parseEnvToArray = (
envValue?: string,
fallback: string[] = []
): string[] => {
if (!envValue) return fallback
return envValue
.split(',')
.map((item) => item.trim())
.filter(Boolean)
}
export default defineSecurityConfig({
allowedRegistryDomains: parseEnvToArray(
process.env.SECURITY_ALLOWED_DOMAINS,
['registry.npmjs.org']
),
audit: {
registry: process.env.SECURITY_AUDIT_REGISTRY
},
outDirs: parseEnvToArray(process.env.SECURITY_OUT_DIRS, ['dist'])
})在执行具体构建或 CLI 命令时,你可以通过注入环境变量来覆盖默认值(Node 20+ 环境直接注入 --env-file=.env 会更方便):
SECURITY_ALLOWED_DOMAINS="npm.company.com,registry.npmjs.org" pnpm wui-security-review check --phase build说明:
allowedRegistryDomains只用于校验.npmrc、package-lock.json、pnpm-lock.yaml、yarn.lock中出现的源域名是否可信audit.registry只用于指定npm audit/pnpm audit请求的审计接口地址
使用指南
本工具库为您提供了在开发、提交以及 CI 等任意环节切入审查的能力:
1. CLI 命令行直接使用
推荐直接跑在 CI 流水线或通过 Husky 的 pre-commit 钩子调用:
# 全局全量源文件构建前审查
pnpm wui-security-review check --phase build
# 自动适配 CI 阶段(使用 json 格式化输出方便程序化解析截断流水线)
pnpm wui-security-review check --phase ci --format json
# 针对 Husky / lint-staged(通过 --staged 指令,仅检查 git 暂存区发生变更的文件提升速度)
pnpm wui-security-review check --phase pre-commit --staged
# 检查并额外输出可视化 HTML 大屏报告(默认输出至项目根目录 security-report.html)
pnpm wui-security-review check --phase build --html
# 指定独立输出 HTML 报告的自定义路径
pnpm wui-security-review check --phase build --html ./reports/dashboard.html
# CLI 默认会打印扫描文件列表;需要脱敏时可显式隐藏
pnpm wui-security-review check --phase build --hide-scanned-files
# 当扫描文件很多时,进一步展开完整列表
pnpm wui-security-review check --phase build --expand-files2. Vite 插件集成
如果不希望额外配 CLI,你可以把它当成普通打包环节的 Plugin 挂载,使得开发(dev)或生产构建(build)时同步报错拦截。
// vite.config.ts
import { defineConfig } from 'vite'
import { createViteSecurityPlugin } from '@wuipkg/security-review/vite'
export default defineConfig({
plugins: [
// 默认会自动寻址当前工程下的 wui-security.config.ts 全局配置
createViteSecurityPlugin()
]
})React + Vite
React 项目无需单独的 React 子入口,直接复用同一个 Vite 插件即可:
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { createViteSecurityPlugin } from '@wuipkg/security-review/vite'
export default defineConfig({
plugins: [react(), createViteSecurityPlugin()]
})3. Webpack 插件集成
为传统的 Webpack 工程提供完全一致的使用体验:
// webpack.config.ts
import { createWebpackSecurityPlugin } from '@wuipkg/security-review/webpack'
export default {
plugins: [createWebpackSecurityPlugin()]
}React + Webpack
// webpack.config.ts
import { createWebpackSecurityPlugin } from '@wuipkg/security-review/webpack'
export default {
module: {
rules: [
// 你的 tsx / jsx loader 配置
]
},
plugins: [createWebpackSecurityPlugin()]
}4. ESLint 静态代码提示并轨
我们将可做静态 AST 分析的安全规则单独整理到了此配置下,让你在写代码的第一时间就在 IDE 收到红色波浪线提示:
// eslint.config.js (ESM flat config)
import lint from '@wuipkg/lint/eslint'
import securityReview from '@wuipkg/security-review/eslint'
export default [
...lint,
// 接入专属的 AST 静态安全审查引擎池
...securityReview
]React + ESLint
React / TSX 工程同样使用这一子入口,但需要宿主 ESLint 配置先具备 JSX / TSX parser 能力;在本仓库里推荐直接与 @wuipkg/lint/eslint 组合使用:
// eslint.config.js
import lint from '@wuipkg/lint/eslint'
import securityReview from '@wuipkg/security-review/eslint'
export default [...lint, ...securityReview]注意:
@wuipkg/security-review/eslint负责导出安全规则本身,不会额外注入 React / TSX parser。 React Router 的 open redirect 检测(例如useNavigate()、<Navigate />)仅由源码扫描规则覆盖, 需要通过 CLI /runSecurityReview/ Vite / Webpack 接入;/eslint子入口不负责这部分语义分析。
React 典型风险示例
// 1. DOM XSS
export const Preview = ({ html }) => (
<div dangerouslySetInnerHTML={{ __html: html }} />
)
// 2. Reverse Tabnabbing
export const Link = () => <a href="https://a.com" target="_blank">Open</a>
// 3. 表单外链劫持
export const PaymentForm = ({ externalUrl }) => (
<form action={externalUrl}></form>
)
// 4. Open Redirect
import { useNavigate } from 'react-router-dom'
export const Login = () => {
const navigate = useNavigate()
const redirect = new URLSearchParams(window.location.search).get('redirect')
navigate(redirect || '/')
return null
}ESLint 规则清单
| 规则名 | 默认等级 | 描述 |
| ------------------------------------------------------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| @wuipkg/security-review/no-dangerous-dom-api | error | 禁止 innerHTML、outerHTML 属性赋值,document.write 和 eval 调用;React 项目应同时配合源码规则检查 dangerouslySetInnerHTML。 |
| @wuipkg/security-review/require-message-origin-check | error | 要求 window.addEventListener('message', ...) 处理器首条语句校验 event.origin。 |
| @wuipkg/security-review/no-unsafe-redirect | error | 禁止直接把 URL 参数(location.search、$route.query 等)写入 location.href 或传给 location.assign/replace。支持递归检查调用链、模板字符串、逻辑表达式等复合表达式。 |
| @wuipkg/security-review/no-sensitive-storage | error | 禁止 localStorage/sessionStorage.setItem 以 token、idCard、phone 等敏感词作为 key 明文存储。 |
API 导出
本包通过主入口 @wuipkg/security-review 导出以下类型和函数:
函数
| 导出名 | 描述 |
| -------------------------------- | ------------------------------------------ |
| defineSecurityConfig(config) | 配置辅助函数,提供完整类型提示 |
| loadSecurityConfig(options?) | 从 wui-security.config.ts 加载并解析配置 |
| resolveSecurityConfig(config?) | 将用户配置与默认值合并为完整配置 |
| runSecurityReview(options) | 执行安全审查,返回完整报告 |
| createReporter(format) | 创建格式化报告器 ('pretty' | 'json') |
| formatPrettyReport(report) | 格式化为终端可读的彩色报告 |
| shouldFailReport(report) | 判断报告是否包含错误级别发现 |
类型
| 导出类型 | 描述 |
| ------------------------------ | ---------------------------------------------------------------------------- |
| SecurityReviewConfig | 用户配置接口 |
| ResolvedSecurityReviewConfig | 合并后的完整配置 |
| ResolvedSecurityRuleSetting | 单条规则解析后的设置(含 level 与 options) |
| SecurityRuleName | 所有规则名联合类型 |
| SecurityRuleLevel | 'off' \| 'warn' \| 'error' |
| SecurityRuleInput | 规则配置输入类型(SecurityRuleLevel \| { level?, options? } \| undefined) |
| SecurityFinding | 单条审查发现 |
| SecurityReviewReport | 完整审查报告(含 findings、suppressedFindings、summary) |
| SecurityPhase | 'pre-commit' \| 'build' \| 'post-build' \| 'ci' |
| SecurityReporter | 报告器接口(含 format 与 render) |
| SecurityReporterFormat | 报告器格式类型('pretty' \| 'json') |
| CredentialDetectContext | detect 回调的上下文参数 |
| CredentialDetectFn | detect 回调的函数签名 |
| RunSecurityReviewOptions | runSecurityReview 的选项 |
License
MIT
