在DAST中设置认证哨兵验证会话有效性
在 CI/CD 中为 DAST 扫描配置认证会话:从登录态注入到扫描结果回归验证
我配完一整套认证变量,点开报告那一刻,满眼都是 302。用户名密码都是从 CI 变量注入的,登录表单字段也填了,可扫描结果和匿名扫描几乎没两样。后来才明白:登录失败时 ZAP 不会喊停,它照样把整轮扫完,只是扫的全是登录页。
这就是为什么我现在配置 DAST 认证,第一件事不是填凭据,而是先想好怎么验证:设置认证哨兵。
哨兵应该怎么设置
思路很简单:在测试环境准备一个只有携带有效会话才能访问的接口,比如返回当前用户信息的 /api/me。匿名请求它,要么是 401,要么被跳转到登录页;带着会话请求,才会返回 200 和用户数据。
对应到 ZAP 配置,就是把这个地址放进爬虫的起始 URL 列表。扫描结束后去 Sites 树里找它:状态码 200 且响应里有用户数据,说明扫描器是真的带着会话在跑;要是 401 或 302,那就是登录没成功,或者扫描中途会话掉了。这个判断没什么模糊空间,比我对着报告猜要痛快得多。
让它真正卡住流水线
光靠眼睛看还不够。我把 gl-dast-report.json 丢给一个小脚本,匹配这个哨兵 URL 对应的状态码,只要不是 200 就以失败退出,让流水线报错。加这几行的意义在于,认证配置从“配了、希望它生效”变成“不生效就报警”。之前那种变量填了、报告照生成、谁也没确认过的状态,其实就是手动祈祷。
几个我踩过的坑
哨兵别选会跳转或会改变会话状态的路径。登出链接是典型反例,ZAP 的爬虫确实会去点它,这也是要在配置里排除登出 URL 的原因。但排除规则要仔细核对,别把哨兵一起排除了。
另外,哨兵只能证明扫描开始时会话是活的。长任务跑到中段 Cookie 过期,它照样是绿的。所以我现在会同时看一眼报告里 200 响应的大致占比,以及 URL 列表里有没有登录后才出现的业务路径。两个信号对得上,我才算踏实。
第一次配置时,建议再跑一次未认证扫描做对照。两份报告放在一起,URL 数量的差距和漏洞类型的变化非常直观,也顺带证明了哨兵确实在工作。

参与讨论
之前踩过的坑,全是靠试错换来的,太真实了