Vue 3 项目大多是前后端分离架构,页面上大量的数据交互通过接口完成,传统的渗透测试往往只关注后端服务,前端构建产物中泄露的敏感信息、接口鉴权缺失等问题却容易被忽略。OWASP ZAP 是一款开源的 Web 应用安全扫描工具,它既提供图形界面方便手工探索,也提供命令行模式和丰富的 API,非常适合嵌入到工程化流水线中。这篇文章就来聊聊怎么把它接进 Vue 3 的项目流程里,让安全扫描变成每次构建的固定环节。

一、先搞清楚 ZAP 的两种扫描模式
ZAP 的扫描分为被动扫描和主动扫描两类,理解这两者的区别是合理使用工具的前提。被动扫描是指 ZAP 以代理身份监听你浏览网站时产生的所有请求和响应,只分析流量本身而不主动发起攻击。这种方式对业务无侵入,风险极低,适合在开发阶段持续运行。比如你在本地跑起 Vue 3 的开发服务器,把浏览器代理指向 ZAP,然后像平时一样点击页面、填写表单,ZAP 就会把流量中暴露的问题记录下来。
主动扫描则是 ZAP 主动向目标发送攻击载荷,用来验证漏洞是否真实存在。它会对每个发现的参数、URL 尝试注入 XSS 载荷、SQL 注入语句等。需要注意的是,主动扫描会对目标产生额外的请求压力,扫描生产环境务必谨慎,一般建议只在测试环境执行。另外,主动扫描应该在被动扫描完成上下文探索之后进行,也就是先用浏览器或者爬虫把站点的页面和接口都访问一遍,让 ZAP 掌握完整的目标结构,否则扫描器只盯着首页,覆盖面会非常有限。
对于 Vue 3 这类单页应用来说还有个特殊问题:路由切换全在前端完成,传统的爬虫可能只抓到入口页面。这就需要借助 ZAP 的 AJAX 爬虫,它会驱动一个真实浏览器内核来执行 JavaScript,模拟用户点击和滚动,从而发现动态渲染出来的路由和接口调用。
二、本地环境搭建与手动扫描实践
第一步是安装 ZAP,可以从官方地址下载对应平台的安装包,也可以直接用 Docker 拉取官方镜像,后者更省事也更利于后续 CI 集成。本地手动测试时,先启动 ZAP,默认代理端口是 8080,然后配置浏览器代理指向 127.0.0.1:8080。如果你的 Vue 3 项目跑在开发模式,记得在 vite.config.js 中配置代理,把接口请求转发到后端,这样 ZAP 才能捕获完整的请求链路。
// vite.config.js 中将后端接口通过 vite 代理转发
export default defineConfig({
server: {
port: 5173,
proxy: {
'/api': {
target: 'http://backend-test-env',
changeOrigin: true
}
}
}
})
代理配置好之后,在 ZAP 中打开 AJAX Spider,输入前端站点地址,让它自动遍历页面。等爬取结束后,切换到 Active Scan 标签页,选择刚才爬到的站点节点发起主动扫描。扫描过程中可以实时查看 Alerts 面板,每发现一个问题,ZAP 会给出风险等级、攻击载荷、对应的 CWE 编号以及修复建议,这些信息后面在复盘时非常有用。
手动扫描适合探索阶段,但要让安全测试真正工程化,就不能依赖人肉点击。ZAP 提供了完善的命令行参数和 REST API,可以把整个扫描流程脚本化,这也是下一节的重点。
三、把 ZAP 扫描集成到 CI 流水线
工程化的核心是自动化。推荐的做法是在 CI 环境里用 Docker 跑一个 ZAP 实例,先构建 Vue 3 项目并启动静态服务,再执行 ZAP 的扫描脚本,最后输出报告并判断是否达到质量门槛。ZAP 官方提供了 zap-baseline.py 这样的 Python 包装脚本,专门用于 CI 场景,它默认只做被动扫描,适合作为快速的门禁检查。
# 在 CI 中执行基线扫描的示例 docker run -v $(pwd)/reports:/zap/wrk/:rw \ -t ghcr.io/zaproxy/zaproxy:stable \ zap-baseline.py \ -t http://vue-app-preview:5173 \ -c zap-rules.conf \ -r scan-report.html \ -I
上面命令中的 -c 参数指向一个规则配置文件,用来指定哪些告警算失败、哪些可以忽略。这在实际项目中非常关键,因为每个项目都有自己的风险基线。比如团队决定任何等级为 High 的问题都直接让流水线失败,Medium 级别的记录在案限期修复,Low 和 Informational 只做记录。-I 参数表示扫描失败时不进入交互模式,CI 环境必须加上。
如果要跑完整的主动扫描,可以把 zap-baseline.py 换成 zap-full-scan.py,但前提是目标环境能承受扫描压力,且环境中的数据可以被污染。更稳妥的折中方案是用 zap-api-scan.py 针对接口做定向扫描,配合扫描上下文配置,只对指定的 API 路径发起攻击。
对于 GitHub Actions 用户,也可以用社区维护的 Action 直接封装好的步骤,或者干脆写一个自定义 Job:先 npm run build,再用 npx vite preview 把构建产物起起来,然后等待服务就绪后触发 ZAP 扫描容器。扫描完成后用 actions/upload-artifact 把 HTML 报告存档,方便团队成员随时查看历史记录。
四、解读报告与处理误报
ZAP 的报告里最常见的告警包括 XSS 风险、缺失的安全响应头、Cookie 未设置 HttpOnly、目录列表暴露等。针对 Vue 3 项目,有几类问题需要特别关注。第一类是构建产物中的 Source Map 文件,如果生产构建把 .map 文件也上传了,ZAP 会报信息泄露,因为攻击者可以通过 Source Map 还原源码。解决方案是在生产环境禁用 sourcemap 或者在部署层拦截 map 文件的访问。第二类是 CSP 响应头缺失,Vue 应用如果通过 v-html 渲染富文本,一旦 CSP 没配好,XSS 风险会被放大,建议在 Nginx 或 CDN 层统一补上 Content-Security-Policy 头。
误报处理也是绕不开的环节。扫描器毕竟是黑盒探测,比如它可能把一个正常返回 JSON 的接口误判为存在 SQL 注入,或者对前端路由的通配路径报出莫须有的目录遍历。遇到这类情况,先在 ZAP 界面里复现该告警的请求详情,确认攻击载荷的实际响应,判断漏洞是否真实。确认是误报后,把该规则的 ID 加进规则配置文件的忽略清单,并附上说明和负责人,这样既保持了流水线的可信度,也留下了审计痕迹。
最后要强调一点,工具扫描只是安全体系的一环。ZAP 能覆盖的是常见的已知漏洞模式,对于业务逻辑漏洞,比如越权访问、支付流程绕过,它无能为力。合理的做法是把自动扫描作为日常门禁,再辅以定期的代码审计和人工渗透测试,多层防线叠加,才能真正守住 Vue 3 应用的安全边界。