十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

OWASP Top 10 漏洞实战:越权、注入、SSRF 与 ZAP 自测

OWASP Top 10 漏洞实战:越权、注入、SSRF 与 ZAP 自测 上周有个做后端的朋友把一份第三方扫描报告甩过来二十多条高危标题写着OWASP Top 10 命中 6 项。他问我第一句话是这玩意儿到底是不是只要装了扫描器就能全查出来这个问题本身就是绝大多数人对 OWASP Top 10 的误解起点。这份榜单确实是目前 Web 安全领域引用最广、最常被拿来当自查提纲的材料但它排的是风险类别不是漏洞清单更不是一套能靠工具一键扫完的检查项。下面我就按自己这几年在项目里反复对照、反复踩坑的顺序把这十大常见漏洞从它到底是什么讲到日常怎么测、怎么修、怎么验证中间会穿插我们实际遇到过的案例、修复代价的对比以及用 OWASP ZAP 这类开源工具落地自测的具体操作。无论你是刚入门的安全爱好者、需要给项目做安全自评的后端还是被甲方安全报告追着改的开发都能从这里拿到能直接用的东西。1. 先把榜单的评选逻辑弄明白否则后面全是白干1.1 它是一份风险共识不是漏洞字典很多人第一次翻 OWASP Top 10会觉得条目太少、太笼统一个A01 失效的访问控制底下包含了几十种具体漏洞形态根本不像一份能逐条打勾的清单。这恰恰是它的设计意图。OWASP 是一个开放社区组织Top 10 的产出方式是收集多家机构贡献的脱敏测试数据统计各类问题在实际应用中的出现频率、被利用难易程度、以及成功利用后的影响面再由从业者投票排序。也就是说它回答的是当前最值得投入精力去防的事情有哪些而不是漏洞一共有多少种。理解了这一点你就会明白为什么有些明明很严重的漏洞没进榜——比如业务逻辑漏洞因为它太依赖具体业务场景没法用统一的 CWE 归类去统计。所以正确的使用姿势是把 Top 10 当成风险优先级排序表用它来分配安全投入的时间和预算而不是当成交付验收的打勾表。我见过团队为了覆盖 Top 10去买了三个扫描器结果 A04 不安全设计那一项从头到尾没人碰过因为扫描器根本扫不出设计缺陷。1.2 2021 版相对上一版的位次变化藏着一堆信息如果把 2017 版和 2021 版放在一起看位次变化本身就是一份行业体检报告。我把关键的变化整理成一张表方便你对照2021 版类别名称2017 版位次位次变化的信号A01失效的访问控制A05升到第一说明越权是当前实际被打穿最多的一类A02加密机制失效A03敏感信息泄露改名换义从信息泄露提升到加密全链路失效A03注入A01从第一降到第三不是注入变少而是框架默认防住了一部分剩下的更隐蔽A04不安全设计新增首次把设计阶段独立成类承认大量问题根因在编码之前A05安全配置错误A06基本稳居前列云环境让它更重要A06自带已知漏洞的组件A09从使用含已知漏洞组件进化到覆盖依赖链全流程A07身份识别与认证失败A02合并了原 A02 认证失效范围更宽A08软件与数据完整性故障新增反序列化、CI/CD 投毒、自动更新链路被单独立项A09安全日志与监控失败A10升一位行业开始承认看不见就等于没防A10服务端请求伪造新增SSRF 在云环境下危害被重新评估直接进榜我从这张表里读出来的最有价值的一条是A03 注入从第一名掉到第三名很多人据此认为注入已经不重要了这是典型的误读。它掉下来一方面是因为主流语言和框架把参数化查询做成了默认行为另一方面是因为统计口径变了——原来单列的 XSS 被合并进了注入类。实际项目里注入依然是利润率最高的漏洞之一只是它从随便试个单引号就报错变成了藏在一个拼接的排序字段参数里。1.3 拿它自查时最容易犯的三个错第一个错是只信扫描器。自动扫描器擅长发现注入、配置错误、已知组件漏洞这类有固定模式的问题对访问控制、不安全设计、日志监控这类需要理解业务语义的问题基本无能为力。一份全是绿的扫描报告不代表你的系统安全。第二个错是按编号顺序修。A01 排第一不代表你项目里 A01 的问题就该最先修。正确的排序依据是外部可达性 × 利用难度 × 影响面我会在第 7 节给一个具体的排序方法。第三个错是把修复当成一次性任务。安全配置错误和组件漏洞这两类是持续变化的今天你的依赖没有已知漏洞明天可能就爆一个。把安全自查做成流程而不是事件这是我从几次被动应急里学到的最大的教训。2. 前三名访问控制、加密、注入这三条路最常被直接打穿2.1 A01 失效的访问控制越权是所有漏洞里的重灾区先分清两个概念。认证回答的是你是谁授权回答的是你能做什么。绝大多数越权问题的根因是认证做了授权漏了。开发同学在写接口时,习惯性地加了一层登录校验然后默认登录用户能看到的数据就是他有权限看的数据这个默认假设就是漏洞本身。常见的形态有几种。水平越权是同一角色用户之间互相访问对方数据最典型的实现就是GET /api/order/1001把 1001 改成 1002 就能看到别人的订单。垂直越权是低权限用户访问了高权限功能比如普通用户直接请求管理员接口。还有一种是接口层完全没校验只在界面上把按钮隐藏了——这属于自己骗自己前端隐藏从来都不是权限控制。我见过最典型的一段错误代码长这样# 错误示范用户身份从请求参数里取等于让攻击者自己声明我是谁 app.route(/api/order/order_id) login_required def get_order(order_id): order Order.query.get(order_id) return jsonify(order.to_dict())这里的问题不在于有没有登录校验而在于校验了身份却没校验资源归属。正确写法必须从服务端会话或令牌里取当前用户 ID再把它作为查询条件的一部分# 正确写法归属校验写进查询条件越权时天然查不到数据 app.route(/api/order/order_id) login_required def get_order(order_id): order Order.query.filter_by( idorder_id, user_idcurrent_user.id ).first_or_404() return jsonify(order.to_dict())这两种写法在功能测试阶段表现完全一样只有在做越权测试时才会暴露差别。修复思路上我建议不要逐个接口去补校验而是做集中式鉴权在框架层面统一挂一个拦截器或中间件规定所有涉及资源的操作默认拒绝必须显式声明访问策略。默认拒绝这个原则听起来简单但它是把越权从偶发漏洞降级为需要显式犯错的关键。另外两个容易被忽略的点CORS 配置写成通配符加允许携带凭据等于给攻击者开了跨站读数据的口子JWT 里塞了 role 字段但服务端每次都信这个字段而不查库一旦密钥泄露或者算法被改成 none整套权限就废了。2.2 A02 加密机制失效把加密当勾选项的代价这一类在 2021 版里从敏感信息泄露改名而来范围一下扩大了很多。它不只看你数据有没有加密还要看你加密得对不对、密钥管得好不好、该用加密的地方有没有用。我从排查经验里把它拆成四层传输层。内网通信不上 TLS 是个很普遍的问题理由通常是内网可信。但现代架构里内网早就不等于可信网络了容器之间的东西向流量、跨可用区的调用都可能经过你不完全掌控的链路。存储层。密码用 MD5 或 SHA1 存是最经典的错误。原因很直白这类哈希设计目标是快而快意味着攻击者可以用 GPU 每秒尝试上百亿次。存密码必须用专门设计为慢的算法比如 bcrypt、scrypt 或 Argon2并且每个用户独立加盐。这里的慢是特性不是缺陷它会让你自己登录时多花几十毫秒却让离线爆破的成本上升好几个数量级。对称加密的模式选择。ECB 模式必须避开因为相同的明文块会产生相同的密文块攻击者即使解不开也能看出数据里的重复模式。想象一下把一张位图用 ECB 加密加密后的图像依然能看出原图轮廓这就是问题所在。用 CBC 或 GCM后者还自带完整性校验。密钥与随机数管理。把密钥硬编码在代码里、提交进版本库是排查时最常见也最让人头疼的问题——因为一旦提交过改密钥就意味着一次完整的密钥轮换。随机数要用密码学安全的随机源语言里的普通随机函数比如各种random系列是伪随机的可预测不能用来生成令牌、会话 ID 或初始化向量。还有一个隐蔽的点备份、日志、缓存、消息队列里往往存在同一份敏感数据的明文副本。你数据库加密做得再好日志里把用户手机号原样打出来等于全白做。2.3 A03 注入SQL、命令、模板、LDAP 的共同点注入类漏洞的本质只有一句话把数据当成了指令。SQL 注入是把用户输入当成了 SQL 语法命令注入是把用户输入当成了 shell 命令模板注入是把用户输入当成了模板代码XSS 是把用户输入当成了 HTML/JS。只要你在某个地方把外来的字符串和可执行的语法拼在同一个通道里注入就可能出现。参数化查询为什么能解决 SQL 注入值得说清楚因为这决定了你会不会用错。参数化查询预编译的机制是先把 SQL 语句的结构发给数据库解析并生成执行计划此时参数位置是占位符结构已经定死了然后再把参数值单独传过去。数据库从头到尾都把这批值当成数据不会重新解析成语法。所以哪怕参数值里带了引号和分号也只会被当成一串普通字符。# 错误字符串拼接输入 OR 11 直接改变语义 sql SELECT * FROM users WHERE name name # 正确占位符传参结构提前固定 cursor.execute(SELECT * FROM users WHERE name %s, (name,))这里有个特别容易被忽略的坑ORM 不等于安全。很多人以为用了 ORM 就万事大吉结果写出了把用户输入拼进原生 SQL 片段的代码或者用 ORM 提供的原始查询接口时又做了一次拼接。我的建议是只要看到 ORM 里有raw、execute、字符串格式化这类关键字出现在查询附近就要停下来看一眼。命令注入的修复思路和 SQL 不太一样。最稳的做法是不要调用 shell而是用参数数组的形式直接执行程序让参数值没有机会被 shell 解析。如果业务上必须走 shell那就只能靠严格的白名单校验——注意是白名单不是黑名单黑名单永远漏。模板注入则是把用户输入直接当成模板内容去渲染。修复原则很简单模板是代码用户输入是数据两者必须在不同的层里处理。用户能改的只有变量不能改模板结构。XSS 严格说也属于注入家族在 2021 版里被并入了这一类。防御核心是输出编码——数据在进入 HTML 上下文时按该上下文规则转义进属性、进 JS、进 URL 的编码规则都不一样不能一把梭。再叠加一层内容安全策略CSP作为兜底即使某个点漏了也能限制脚本执行。我以前也觉得 CSP 配置麻烦直到有一次靠它拦住了一个漏掉的输出点才真正重视起来。3. 中间四个设计、配置、组件、认证问题往往出在代码之外3.1 A04 不安全设计写第一行代码之前就已经埋了这一类是 2021 版新增的也是扫描器完全无能为力的一类。它和实现有 bug是两个层面的事情实现有 bug 是设计是对的代码写错了不安全设计是代码没写错但设计本身就没考虑威胁。举几个我在实际项目里见过的例子。优惠券接口设计成POST /coupon/receive只校验用户是否登录没有校验该用户是否已领取过这个业务约束结果被脚本刷了十几万张。密码找回设计成回答三个密保问题答案是可以枚举的公开信息。秒杀系统在应用层判断库存没在数据库层面用条件更新做原子扣减高并发下超卖。这些都是代码质量很好、单元测试全绿的模块但设计上就缺了一层。对付这类问题的标准做法是威胁建模听起来很重实操可以很轻在设计评审阶段画一张数据流图标出所有跨越信任边界的地方用户到服务、服务到数据库、服务到第三方然后对每个边界问四个问题——谁能改这里的输入、改了会怎样、我能不能发现、发现了能不能拦住。这四个问题问下来八成设计缺陷在动工前就能被发现。我自己的习惯是额外写一份误用用例紧跟在用户故事后面。比如用户故事是用户可以使用优惠券下单误用用例就写用户重复提交同一张优惠券、用户提交别人的优惠券、用户并发提交十次。这些用例直接变成测试用例比事后做渗透测试便宜得多。3.2 A05 安全配置错误默认值、详尽报错和忘记关的端口配置错误之所以常年排在前列是因为它是系统性的——一套错误的基线配置会被复制到几十上百个实例上而且经常是自动化部署带着一起复制。常见的坑包括默认账号没改、示例应用没删、目录列表没关、错误页返回完整堆栈、不必要的 HTTP 方法开着比如 PUT、DELETE 直接可用、云存储桶权限开放、容器以 root 运行、调试端口暴露。这里有个近几年出现频率特别高的坑框架自带的运维端点没加鉴权。Spring 生态的 Actuator、各类健康检查与指标端点默认可能暴露出环境变量、配置项甚至堆栈信息。健康检查又常常必须对外开放否则负载均衡没法探活于是就成了一个敞开的信息泄露口。正确做法是把探活端点和信息类端点拆开前者开放且只返回状态码后者走内网并加认证。修复配置错误最有效的手段是把配置当代码管理所有环境的配置进版本库敏感值用密钥管理服务注入任何配置变更走评审然后用自动化脚本定期比对线上配置和基线配置的差异。我一般会写一个简单的检查脚本把几十条基线规则跑一遍输出不一致项挂在定时任务里。这比人工巡检靠谱也比买一套商业合规平台便宜。配置基线本身不用从零造。OWASP 有专门的配置检查清单主流中间件和框架的官方文档里也有安全配置章节交叉对照一遍就能整理出适合自己技术栈的版本。关键是这份基线要有人维护新引入一个组件就补几条规则。3.3 A06 自带已知漏洞的组件依赖清单本身就是攻击面现代项目的依赖结构是这样的你直接声明的依赖可能只有二十个但拉下来的间接依赖可能有八百个而你根本不知道这八百个里有哪些、用的什么版本。这就是 A06 的现实困境。这类问题的杀伤力有多大看那次 Java 生态里被几乎所有项目间接依赖的日志组件出现远程代码执行就明白了——一个你从来没主动引用过的库能让整条业务线在几小时内被动应急。它之所以影响那么广正是因为间接依赖这个特性很多团队排查自己有没有受影响时第一步是懵的因为根本不知道自己的依赖树里有没有它。治理这类问题需要三件事同时到位第一生成依赖清单。也就是常说的 SBOM把你所有直接和间接依赖及其版本列出来。主流生态都有现成工具下面这张表是我常用的组合生态扫描方式说明Java / MavenOWASP Dependency-Check 插件绑定到构建流程构建时即产出报告Java / GradleDependency-Check Gradle 插件同上支持配置失败阈值Node.jsnpm audit、第三方 SCA 工具npm audit 内置但覆盖面有限Pythonpip-audit、Safetypip-audit 可直接扫虚拟环境容器镜像Trivy 等镜像扫描器除了语言依赖还会扫系统包全仓统一平台内置的依赖更新机器人自动提 PR 升级有漏洞的依赖第二建立升级通道。很多团队不是不知道有漏洞而是这个库版本太老升级要大改。这种情况我建议先把升级评估做成常规工作而不是等爆漏洞时才评估。哪怕暂时升不上去也要记录在案并给出缓解措施比如加一层过滤、限制该功能的外部可达性。第三区分真实风险和告警噪音。扫描器报的是你用了含已知漏洞的版本但漏洞能不能被触发取决于你有没有用到那个有问题的功能、外部能不能到达那个入口。所以收到告警后的第一步永远是评估可利用性而不是盲目升级盲目升级引入的新问题有时候比原漏洞更麻烦。3.4 A07 身份识别与认证失败撞库、会话和那个被误解的密码策略这一类覆盖的东西比字面意思宽得多包括弱口令、撞库、会话管理不当、多因素缺失等。我把它们分成三组来看。第一组是凭据本身的问题。撞库是目前最主要的外部入侵手段之一原理是利用用户在多个站点复用同一套账号密码拿别的站泄露的凭据来撞你的站。防撞库靠单一手段防不住得组合拳登录失败次数限制、异常登录的二次验证、以及基于设备指纹和行为特征的风险评分。这里有个细节限制策略如果只按账号维度做攻击者换账号就能绕只按 IP 维度做攻击者换 IP 就能绕。两个维度都要并且要防止策略本身变成拒绝服务的手段——锁定账号的机制被用来批量锁死正常用户这种事我见过。第二组是会话管理。登录成功后要重新生成会话 ID否则会出现会话固定攻击攻击者先诱导用户使用一个他知道的会话 ID等用户登录后这个 ID 就变成了已认证状态。会话要有超时注销要让服务端会话立即失效不能只是前端清掉本地存储。JWT 场景还要额外注意几个坑算法被改成 none 而服务端不校验、签名密钥过弱可被离线爆破、令牌有效期设得过长且没有撤销机制。JWT 无状态的代价就是难撤销如果业务上有强制下线需求就必须额外维护一份黑名单或版本号。第三组是密码策略的认知偏差。复杂度要求大小写加数字加符号实际上会引导用户产生可预测的模式比如Password1!这种。现在的共识是长度优先鼓励使用长口令或口令短语配合黑名单过滤常见弱密码和已泄露密码比强制复杂度更有效。另外登录接口一定要走加密传输这个在 2.2 节已经说过但值得在认证这个场景里再强调一次。4. 后三名完整性、日志和 SSRF最容易被降级处理4.1 A08 软件与数据完整性故障从反序列化到流水线投毒这一类也是新增的它关注的是一条很容易被忽视的链路你信任的那些数据和代码在到达你之前有没有可能被人改过。反序列化是最经典的形态。把不可信的数据反序列化成对象本质上是让外部输入决定了你程序内部的类型和结构在 Java、Python、PHP 里都有对应的危险点。Python 的 pickle 尤其要注意它的设计目标就不是处理不可信数据官方文档里写得很清楚。防御原则很干脆不要反序列化不可信来源的数据改用 JSON 这类纯数据格式它们不会在解析时构造任意对象。自动更新和第三方脚本是另一个高频点。前端引入 CDN 上的脚本时要加子资源完整性校验让浏览器验证脚本内容哈希防止 CDN 被篡改后脚本被替换。后端的自动更新机制要验证签名不能只靠传输层加密——传输层保护的是传输过程签名保护的是内容本身。CI/CD 流水线本身也是攻击面。构建脚本能拿到部署凭据一旦有人能往构建流程里插一脚比如通过一个恶意 PR 修改构建配置就能拿到生产环境权限。所以流水线的权限要最小化生产部署凭据不要对所有分支开放构建产物要能追溯到具体的提交。4.2 A09 安全日志与监控失败出事之后一片黑这一类在技术上危害最小因为漏洞本身不会直接造成数据泄露。但它的实际影响可能最大因为它决定了一次入侵会被发现还是会在系统里潜伏几个月。我见过的最难受的场景是确认被入侵了但查不到从哪个入口进来的、什么时候进来的、拿走了什么因为日志里只有访问记录没有登录失败、没有权限拒绝、没有异常输入。要记录什么我一般按这几个方向列认证相关成功、失败、锁定、密码重置、授权相关权限拒绝、越权尝试、输入校验失败、关键业务操作金额变更、权限变更、数据导出、以及管理后台的所有操作。日志要结构化方便检索和关联要脱敏用户手机号、身份证号、令牌这些不能原样落盘要集中收集并且写到攻击者拿不到的地方——如果日志只存在被入侵的那台机器上攻击者第一件事就是删日志。还有一点是告警。日志不告警等于没记人不会天天去看日志文件。告警阈值要调太松会被忽略太严会疲劳。我推荐从少数几条高置信规则开始比如短时间大量登录失败、非工作时间的管理操作、单账号短时间大量数据导出先把这几条跑顺再逐步加。4.3 A10 服务端请求伪造让服务器替你访问不该访问的东西SSRF 的核心场景是业务需要一个根据 URL 获取内容的功能而 URL 由用户提供。常见于图片抓取、链接预览、Webhook 通知、文档转换、PDF 生成、以及各种代下载接口。危险之处在于服务器所在的网络位置和普通用户完全不同。服务器能访问内网服务、能访问本机回环地址上的管理接口、能访问云环境中那个提供实例元数据的固定地址很多云厂商都会在实例内部暴露一个固定 IP 的元数据服务用于获取实例信息和临时凭据。如果不做限制攻击者可以通过你的接口去探测内网端口、读取内网服务响应甚至拿到云上的临时凭据。这类漏洞从看起来只是个请求转发直接升级成整个云账号失守就是它 2021 年能直接进榜的原因。缓解措施要分层做缓解手段作用注意点目标域名白名单从源头限制可访问目标白名单要严格不支持通配过宽的规则禁止跟随重定向防止第一跳合法、第二跳进内网很多绕过都靠重定向解析后校验 IP防止域名解析指向内网地址必须在请求发起的实际 IP 上校验出网隔离让服务器根本无法访问内网最彻底但架构改造成本高云平台侧策略强制元数据服务使用会话令牌属于平台能力成本低优先开需要特别提醒的一点是 DNS 重绑定这类绕过你在校验时解析域名得到的是公网 IP但请求真正发起时 DNS 又解析成了内网 IP校验就失效了。要防这个必须在校验和实际连接之间保持一致性比如把校验过的 IP 固定下来直接连接而不是重新解析一次域名。5. 把这份清单落到日常自测OWASP ZAP 怎么用才有效5.1 先明确 ZAP 的能力边界OWASP ZAP 是一款开源的 Web 应用安全测试工具支持图形界面和命令行两种模式能做代理抓包、被动扫描、主动扫描和 API 扫描。它在同类工具里最大的优势是开源免费、可脚本化、能集成进流水线。但它的能力边界也清楚它擅长发现注入、XSS、配置错误、信息泄露、已知组件漏洞这类有特征可匹配的问题对访问控制、不安全设计、业务逻辑问题基本无能为力——前面几节里反复强调的那些重灾区恰恰是它扫不到的。所以正确的用法是把它当成一台基础体检仪用来快速筛掉一批低垂果实然后人工去做它覆盖不了的那部分。上一节说的越权、设计缺陷只能靠人工设计和审查。上手路径我建议这样安排。先跑代理模式把浏览器或客户端的代理指向 ZAP 的监听端口正常点一遍业务流程ZAP 会在后台做被动扫描从流量里识别问题。这一步不做任何攻击性请求完全安全适合生产前的初步摸底。被动扫描有结果之后再针对具体接口用主动扫描也就是 ZAP 自己构造测试请求去探测。注意主动扫描会产生大量请求可能会影响业务数据不要在不可控的生产环境上跑。如果不方便配置浏览器代理可以直接用容器化的命令行模式跑基线扫描docker run --rm -t ghcr.io/zaproxy/zaproxy:stable \ zap-baseline.py -t https://your-app.example.com -r report.html基线扫描的理念是只做被动扫描不主动攻击适合挂在每次构建之后跑一遍。想跑主动扫描就用zap-full-scan.py它有明确的攻击行为务必只对自有系统使用。API 接口则用zap-api-scan.py配合 OpenAPI 描述文件导入这样可以覆盖到前端页面里没有暴露出来的接口。注意任何扫描行为都只能对你拥有或获得书面授权的系统执行。未经授权对他人系统发起扫描在很多地区都属于违法行为这一点没有灰色空间。5.2 文件上传接口怎么用 ZAP 测文件上传是很多系统里最容易出问题又最容易被漏测的接口因为它涉及好几个独立的校验点任何一个漏了都可能被绕过。ZAP 本身对上传接口有相应的插件支持能识别出一些常见问题但这类接口我更建议工具初筛 手工精测结合。手工精测的思路是逐个拆解服务的校验点。第一关是扩展名校验测试时试一下双扩展名、大小写混用、末尾加点或空格这类绕过方式看服务端是按哪个部分判断的。第二关是内容类型校验用 ZAP 的请求编辑器把 multipart 请求里的 Content-Type 改掉比如把一个文本文件声明成图片类型看服务端是只信头部声明还是真的检查了文件内容。第三关是文件内容校验真正的防御应该读取文件头部的特征字节做判断而不是看后缀名。第四关是存储位置上传的文件如果落在 Web 可访问目录里并且服务器会解析该类型那就很危险正确做法是存到 Web 根目录之外通过应用层的下载接口读取。还有两个特别容易忽略的点一是文件名的处理如果用原始文件名拼接路径就可能出现路径穿越把文件写到不该写的位置所以必须重命名二是并发和资源限制上传超大文件、上传大量文件都可能被用来耗尽磁盘或触发拒绝服务。防御上我的建议是做成一个固定顺序的检查链先限制请求体大小再按白名单校验扩展名再按文件头校验真实类型再重命名存储到非 Web 目录最后用独立的域名或对象存储提供下载并且给下载响应加上强制下载的头部避免浏览器直接渲染。这条链上任何一环缺失前面几环的价值都会打折扣。5.3 报告怎么看把误报和真漏洞分开ZAP 的报告里每条告警都有风险级别和置信度两个维度很多人只看风险级别忽略了置信度。置信度低的结果大概率是误报需要人工确认置信度高且风险级别高的才是优先处理项。我处理报告的习惯是分三档。第一档是直接能确认的真问题比如响应头里暴露了服务端版本、错误页返回完整堆栈、缺少必要的安全响应头这类几乎不需要验证改就是了。第二档是需要复现验证的比如报了一个疑似 SQL 注入我会拿请求编辑器手工发一次改过参数的请求观察响应差异确认能利用再修。第三档是信息类告警比如发现了某个备份文件、某个接口需要 POST 但允许 GET这类不一定有直接危害但通常是更大问题的线索值得顺着看一眼。误报的处理也有技巧。与其在报告里逐条标注不如把确认过的误报规则沉淀到工具配置里下次扫描不再报同样的东西。否则你每次都要重新过滤一遍上百条告警用不了几次就没人看报告了——安全流程失效很多时候不是因为技术不够而是因为噪音太多。6. 从 Web 走到智能体2026 那份新清单在关注什么6.1 传统 Top 10 为什么盖不住智能体场景传统 Top 10 的隐含前提是系统对每个请求的响应是可预测的问题的根源在于输入校验、权限判断、配置这些环节。而智能体应用的前提变了——它会自己决定下一步做什么会调用工具、读写记忆、串联多个步骤去完成一个目标中间过程不完全由开发者预先定义。在这种架构下用户输入可能来自网页内容、第三方文档、其他智能体的消息这些都可能悄悄改变它的行为目标。信任边界从请求到响应变成了目标到一连串行动原来那份清单自然就不够用了。社区里已经在讨论专门面向智能体应用的 Top 10 清单方向是把智能体特有的风险单独归类。下面这些是公开讨论中反复出现的几类我按自己的理解整理出来供你评估自己项目时做参考。6.2 智能体场景下新增的几类典型风险提示注入与目标劫持。这是最核心的一类。攻击方式是把指令藏进智能体会读到的内容里——一段网页文本、一份上传的文档、一条看起来正常的数据记录。智能体读到之后可能把它当成指令执行从而偏离原本的目标。它的麻烦之处在于没有输入校验这种清晰的修复点因为对人类来说是指令、对模型来说是数据边界是模糊的。缓解方向是架构层面的把不可信内容隔离处理限制它能触发哪些动作关键动作必须有人确认。工具与权限过度授予。开发者为了让智能体能干更多事一口气给它几十个工具和很宽的凭据权限这是特别常见的做法。但智能体一旦被劫持这些权限就是攻击者的权限。最小权限原则在智能体场景比在传统应用里更重要因为它的行为更难预测。记忆与知识库投毒。很多智能体会把交互历史或外部知识存进向量库后续检索时再拿出来用。如果写入的数据没做校验攻击者可以通过一次交互污染记忆让它在之后很长时间里持续做出错误判断。这类问题排查起来很痛苦因为症状和原因之间隔了很久。智能体之间的信任传递。多智能体架构里A 智能体的输出会成为 B 智能体的输入。如果中间没有任何校验一个被劫持的智能体就能把恶意指令传递给整个链路上的其他智能体甚至在传递过程中被放大。高影响操作缺少人工确认。让智能体自主执行删除数据、发起转账、修改权限这类操作出错的代价太高。人在回路不是效率的对立面而是必要的一道闸。可观测性不足。智能体的决策过程比传统程序难追踪如果只记录最终的输入输出出问题之后根本无法定位是哪一步偏了。需要记录每一次工具调用、每一次检索结果、每一步的中间推理摘要。6.3 现在就能做的准备如果你正在做智能体相关的项目我建议先把这四件事做了。给每个智能体单独分配凭据不要复用人的账号也不要共用一套凭据所有工具调用走一层集中代理在那一层做权限判断和审计而不是散落在各处对高影响操作强制加人工确认确认界面要展示清楚它到底要做什么而不是一个笼统的同意按钮最后把输入侧和输出侧都当成不可信模型吐出来的代码或命令不要直接执行要经过和你对待外部输入一样的校验流程。这套思路和传统安全的差别没那么大核心还是那三条最小权限、默认拒绝、全程可审计。变的只是被保护的对象从请求变成了目标驱动的一串行动。7. 一份能落地的自查顺序和验证方法7.1 别按编号修按可利用性排优先级拿到一份自查清单最忌讳的就是从第一条往下改。同样是高危修复顺序对实际风险的影响可以差出一个数量级。我的排序依据是四个因素的乘积外部可达性能不能从公网到达、前置条件需不需要登录、需不需要特定角色、利用难度有没有现成工具、要不要构造复杂请求、影响面泄露单个用户数据还是全量数据。按这个标准优先级大致是这样排的优先级典型问题理由最高未授权的访问控制缺陷、公网可达的注入、SSRF外部可直接利用无需前置条件一次成功就拿到数据高认证绕过、会话固定、上传接口的任意文件写入需要少量前置条件但成功后可直接提权中配置错误暴露的敏感信息、加密机制失效单独利用影响有限但常作为攻击链的一环中低依赖组件的已知漏洞需要评估实际可达性很多只在特定功能触发低日志与监控缺失、安全响应头缺失不直接导致泄露但属于基础设施短板应持续补齐有一点需要说明这个顺序是修复顺序不是重视程度。日志和监控虽然排在最后但它决定你能不能发现上面那些问题正在被利用长期看值得单独投入。7.2 修完怎么验证才算不是自欺欺人我见过太多已经修复最后又被同一条路径打穿的情况原因基本都是验证方式不对。验证修复只做功能还正常是不够的必须做三件事。第一重放原始请求。把当初证明漏洞存在的那个请求原样再打一次看是否被拦住。注意要看的是响应内容而不是状态码有些修复只是把 200 改成了 200 加空数据实际上数据还是泄露的。第二用变体再试一遍。如果你只修了GET /api/order/1001这一条路径那试试同名的 POST、试试批量接口、试试导出接口。很多修复只覆盖了报告里提到的那一个点旁边同源的接口完全没动。第三把验证脚本化。把确认过的用例写进回归测试每次发布都跑一遍。这一步的价值在半年后才会体现出来——某次重构改动了鉴权中间件的顺序只有回归用例能第一时间发现。最后再分享一个我自己的习惯修完一批漏洞之后不要急着庆祝回头看看这批漏洞有没有共同的根因。如果发现五条里有三条都是鉴权写在业务代码里那真正该修的是架构而不是那三个接口。把单点修复变成机制改进是我觉得做安全最有杠杆的一件事。
返回列表