当所有组件都处于旧版本时,系统可能是安全的;当所有组件都升级到新版本时,系统也可能是安全的;但在两者之间的几个小时里,访问边界仍可能失效。滚动发布会让一个请求进入旧服务,下一个请求进入新服务。浏览器可能继续运行旧前端,而 API 已经改变。功能开关可能处于开启、关闭、定向命中或回退值状态。工作进程可能执行一条在角色撤销之前创建的消息。数据库已经扩展了结构,但新旧写入端仍在并存。

这正是针对过渡状态开展发布前应用安全测试要回答的采购问题:当版本、凭证、开关、消息和数据正在变化时,关键安全不变量是否一直成立?只在全新 staging 环境中跑通正常路径,无法回答这个问题。

设想一个虚构的多租户报表产品。租户 A 的用户可以申请导出租户 A 的数据。某次发布把授权判断从导出服务迁移到共享策略组件。此时 UI 已更新,一半 API Pod 仍是旧版本,角色变更前创建的导出任务还在队列中,授权决策缓存还会保留数分钟。新旧 endpoint 都能通过普通正常路径测试,但任何路径在任何时候都不能跨入租户 B。用户的租户 A 导出权限被撤销后,排队任务也必须遵守产品约定的撤权后契约。这个例子只是说明方法,并非真实客户案例。

测试对象是安全不变量,而不是某个构建版本

先写出一句必须在整个过渡期保持为真的陈述。例如:“角色 R 被撤销后,该主体不能通过任何同步或延迟路径读取或生成租户 A 的数据。”另一个不变量可以是:“为租户 A 认证的请求,无论服务版本或开关状态如何,都不能选择租户 B 的对象。”

这句话必须具有可操作的细节:主体、资源、动作、边界、撤销事件和允许的延迟。“撤销很快”无法测试;“所有在线读取在 30 秒内拒绝旧会话,且任何特权延迟任务不得在此后开始执行”可以测试。如果产品有意允许已经合法受理的任务在撤权后完成,应把它记录为业务规则,并测试更精确的承诺:任务携带的来源、租户、权限范围和执行身份必须不可变,不能被调用方可控数据替换。

这一方法补充了更广泛的产品上线前渗透测试指南。该指南帮助确定资产、角色、测试深度和发布标准;本文的覆盖单位不同,是在部署期间真实存在的每个状态中重复验证同一个不变量。

在发布窗口前建立过渡状态矩阵

矩阵的坐标轴来自发布计划,而不是通用漏洞清单。记录哪些服务器和工作进程版本会并存、哪些客户端版本仍然活跃、哪些开关影响受保护路径、凭证与授权决策可以缓存多久、哪些消息会比原请求活得更久,以及哪些结构迁移步骤会改变旧代码能够读写的数据。

不要穷举所有理论组合。选择当前、即将上线、回退和高风险状态,优先覆盖跨越信任边界或可能保留陈旧权限的组合。

左右滑动查看对照

要验证的状态受控设置拒绝断言正向对照应保留的证据
初始/当前状态旧客户端、旧服务、当前结构跨租户主体被拒绝同租户已授权主体成功构建标识、主体、租户、决策、关联 ID
混合版本新旧服务或工作进程都可接收请求每个版本都拒绝已撤权或外租户请求已授权请求到达每个版本并成功路由证明和每个版本的独立结果
开关开启/关闭强制进入每条安全相关分支任一分支都不能扩大权限合格主体在两条预期路径中成功开关上下文和实际计算值
开关回退在约定测试环境中制造计算失败回退值不能绕过服务端策略证明回退分支已运行;采用允许动作或独立就绪检查计算错误、回退值、服务端决策
已撤销的旧凭证先证明会话有效,再撤销角色或授权同一凭证在约定时限内被拒绝新鲜的已授权凭证继续成功签发、撤销、请求与决策时间
延迟事件将无害的特权任务保留到撤权或换租户之后执行符合约定的变更后规则等价且当前获授权的任务成功消息身份、不可变安全上下文、工作进程版本
回滚或前滚在当前结构和策略下验证获批的旧代码回滚或前向修复版本任一路径都不能恢复陈旧权限或跨越租户边界兼容的已授权操作成功结构版本、代码版本、实际路径、结果

正向对照不可缺少。如果禁止请求和允许请求都失败,通常证明的是故障或测试装置错误,而不是访问控制有效。刻意采用失败关闭的回退是例外:应记录受保护功能有意不可用,证明系统确实选择了回退分支,并使用一个必须保持可用的独立就绪检查或允许动作作为对照。该结果应标记为失败关闭导致的预期不可用,不能表述为功能完全可用。证据还应证明实际处理动作的版本,但不能泄露令牌或敏感记录。

分别验证新旧应用路径

滚动发布系统会逐步缩减旧副本,同时扩展新副本。并存是正常机制,不是罕见边界情况。因此测试环境需要可靠地定向或识别每个版本,例如测试专用路由规则、只对已授权测试工具返回的版本标头、工作进程池标签或追踪元数据。反复随机请求,直到日志“看起来包含两种版本”,所得证据很弱。

两个兼容方向都要测:旧客户端到新服务器,以及在真实发布拓扑允许时的新客户端到旧服务器。对每个能够执行受保护动作的公开 API、导出、搜索、客服入口和后台路径重复不变量。UI 隐藏按钮不构成拒绝;服务器必须拒绝直接请求。

策略或数据变化后,旧代码尤其值得关注。回滚可能恢复可用性,同时也恢复旧授权缺陷。“旧二进制可以启动”和“旧二进制遵守当前租户与撤权规则”是两个不同的验收标准。

功能开关会产生贴近授权策略的额外状态

功能开关不会自动成为授权控制。客户端可见的开关可能只隐藏界面,而服务器 endpoint 仍可直接调用。服务端开关可以合法地选择策略;一旦如此,计算值、回退值、定向上下文和失败模式就是安全设计的一部分,必须按策略状态测试。

使用确定性的合成上下文得到开启、关闭、定向命中和回退状态。在服务器端验证不变量。回退必须产生明确且经过评审的结果;“SDK 返回什么就用什么”不是验收规则。

还要验证客户端与服务器判断不一致的情况。旧浏览器可能显示原有流程,而服务器已应用新开关规则。安全结果可以是明确拒绝,也可以是兼容响应,但不能无声进入未经评审的旧路径。

权限撤销必须快于会话、令牌和决策缓存

有效测试从一个被证明可用的凭证开始。先记录同租户操作成功,再撤销角色或授权,然后通过所有可用的新旧服务路径重放同一个无害动作。OAuth 撤销 endpoint 返回 HTTP 200 本身不是充分证据:标准允许对本来就无效的令牌返回相同状态,也承认服务器之间传播撤销信息可能有延迟。

根据系统风险模型约定撤销时限。按记录的探测频率分别检查每条路径,同时保留最后一次接受和首次进入持续拒绝区间的结果;检查要覆盖约定时限及额外观察窗口。报告应给出观测边界,例如“第 20 秒仍接受,从第 25 秒起到 90 秒窗口结束的每次探测均被拒绝”,而不应宣称精确传播时刻。若拒绝后再次接受,应判为失败。范围包括服务端会话、自包含 access token、refresh token、策略决策缓存、网关缓存、长连接,以及存在时的模拟登录或客服会话。

会话管理建议在权限级别变化后更新会话标识并销毁旧标识。这是有用的控制,但测试仍要观察实际行为。旧会话、新会话和新鲜的已授权对照都应分别运行,否则某一缓存层的失败可能被误判为全系统撤权成功。

延迟消息需要明确的授权契约

队列把受理时刻和执行时刻分开。标准队列可能重复投递同一消息,因此处理器要具备幂等性。安全还要回答另一个问题:工作进程最终执行时,依据的是谁在什么时候拥有的权限?

并不存在“撤权后必须取消所有先前任务”的通用答案。已经提交的付款可能必须完成,计划导出则可能需要在执行时重新授权。应按操作定义规则。对于特权延迟动作,实用的消息上下文通常包括不可变的租户、主体或服务身份、动作、资源范围、授权版本、受理时间和关联 ID。执行时,所有可变 payload 字段都应视为不可信。

可复现的合成测试可以暂停一次无害导出或通知,撤销发起者权限,部署混合工作进程池,再释放消息。一个等价且当前获授权的任务作为正向对照。如果平台提供经授权的 redrive 机制,可重复投递一次。断言必须检查最终副作用,而不只是日志中的“denied”:不应出现外租户文件、通知、索引条目或回调。

迁移安全决定回滚是否真实可用

结构迁移常采用 expand、migrate、contract 顺序,让新旧应用版本在重叠期都能处理数据。数据库集群发布文档明确描述了混合应用版本,并建议等所有实例进入新路径后再删除旧结构。这是有价值的部署模式,但并不能证明某次具体迁移已经安全。

把每个结构步骤映射到不变量。扩展阶段,旧读取端会不会把缺失的 tenant 或 policy-version 字段解释成全局访问?双写阶段,一个表示是否获得更严格标签,而另一个仍保持宽权限?回填以什么身份更新数据,能否跨越租户边界?收缩阶段是否删除了旧授权路径仍需要的列、数据库键或历史记录?

发布门槛必须区分可逆与不可逆状态。在破坏性 contract 之前,回滚可能只是重新部署旧代码;之后同一动作可能无效,因为旧代码不理解新数据,或无法执行当前策略。获批响应可能改为前滚、在隔离环境中恢复,或发布单独测试过的补偿版本。把所有发布都称为“可回滚”,会掩盖这一决策。

用五个步骤完成授权的合成测试

使用合成租户 A 与 B、测试角色、随机对象标识和无害记录。书面约定授权范围、流量限制、停止条件、测试窗口、证据保留方式,以及是否允许暂停工作进程或队列。回答不变量问题不需要无控制扫描或破坏性请求。

过渡状态验收路径
  1. 基线在撤权前证明旧凭证和当前已授权对照都能到达目标资源。
  2. 过渡让系统进入一个具名的混合版本、开关、队列或迁移状态,并证明实际处理动作的版本。
  3. 安全事件撤销角色、租户成员资格、会话或授权,并记录权威时间戳。
  4. 成对检查通过所有可用同步和延迟路径执行禁止动作及其已授权正向对照。
  5. 决策将观察到的延迟和副作用与不变量比较;复测修复版本,或在不可逆门槛前停止。

记录应可复现且保持最小化:场景 ID、代码与结构版本、开关状态、合成身份、相关时间戳、决策来源、请求或消息关联信息、观察结果和脱敏证据。保存令牌哈希或不透明标签,而不是有效秘密。通过只表示该不变量在指定状态和窗口中成立,不证明所有组合,也不证明没有其他漏洞。

如果测试后候选构建、开关定向规则、授权缓存有效期、工作进程行为或迁移顺序发生变化,应重新打开受影响的矩阵行。再次测试变更路径及其相邻过渡状态,才能继续用这些证据支持发布。先前的通过结果只属于已记录的配置,不能自动批准另一次发布。

把矩阵转化为发布决策和清晰的渗透测试简报

这项工作比整套产品评估更窄,又比正常路径回归更深。当发布改变授权、身份、租户路由、长会话、由开关控制的服务端行为、队列、工作进程或数据表示时,它很有价值。由变更触发的渗透测试指南可帮助判断某个变更是否需要人工测试;过渡矩阵随后定义这次变更中“已测试”的具体含义。

独立评估前,应约定不变量、过渡图、可到达的新旧版本、开关控制方式、撤销时限、延迟动作语义、结构门槛、合成账号、环境差异和停止条件。有用的交付物包括完整状态矩阵、实际测试的版本与状态、成对正负结果、观察到的传播窗口、副作用、可复现发现以及边界清楚的复测记录。报告还应列出无法安全创建的状态。

当独立证据有助于发布决策时,Pentest.red 可以把这一方法纳入经授权的Web 应用渗透测试。可以先在范围规划器中列出租户、角色、发布阶段、工作进程、开关和回滚限制,再讨论时间与交付物。最终目标是对一个精确问题给出可辩护的答案:当应用处于版本之间时,安全规则是否仍然成立?

PENTEST.RED

讨论渗透测试范围与报价

首先明确系统、访问权限、限制条件和预期证据。

准备测试范围

本文以深入研究为基础,经过编辑整理,注重清晰表达和实际应用。

PENTEST.RED / RED JOURNAL