Envoy ext_authz 过滤器的 UAF 修复详解:HTTP 鉴权拒绝请求路径上的内存安全修复
Envoy ext_authz 过滤器的 UAF 修复详解HTTP 鉴权拒绝请求路径上的内存安全修复【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy导读本文基于 Envoy 仓库中 changelogs/current/bug_fixes/ext_authz__fix_uaf_when_rejecting_request.rst 记录的漏洞修复CVE-2026-50572展开深入剖析 ext_authzExternal Authorization外部鉴权过滤器在通过 HTTP 协议调用外部鉴权服务并拒绝请求时存在的 use-after-freeUAF释放后使用内存安全问题及其修复。读完本文你将掌握 ext_authz 过滤器的完整请求处理链路、UAF 漏洞的成因与触发场景以及 Envoy 如何通过生命周期管理和引用计数机制从根本上消除此类风险。一、安全公告内容与影响面根据 changelogs/current/bug_fixes/ext_authz__fix_uaf_when_rejecting_request.rst 的官方记录本次修复针对的是安全公告CVE-2026-50572对应 GitHub Advisory GHSA-q8wp-gf7q-m8cv问题定性为Fixed UAF when ext_authz over HTTP causes request to be rejected. 修复了 ext_authz 通过 HTTP 调用鉴权服务并拒绝请求时产生的释放后使用问题。这条变更记录言简意赅却指向一个安全敏感的领域HTTP 传输模式下的 ext_authz 过滤器。该过滤器本身承担着网关的访问控制职责一旦在拒绝deny路径上出现 UAF攻击者可能借机触发崩溃拒绝服务甚至进一步的内存破坏。同目录下还有一条姊妹修复 changelogs/current/bug_fixes/ext_authz__fix-handling-of-pathless-requests.rstCVE-2026-73547修复的是无 URI 路径请求如 CONNECT导致进程异常终止的问题两者共同构成近期 ext_authz 过滤器在 HTTP 模式下的安全性加固。二、背景ext_authz 过滤器在 HTTP 模式下的工作流2.1 过滤器在 Envoy 中的定位ext_authzExternal Authorization是 Envoy 内置的核心 HTTP 过滤器允许 Envoy 在将请求转发到上游之前先调用一个外部鉴权服务进行校验。它支持两种传输协议gRPC 模式使用envoy.service.auth.v3.AuthorizationgRPC 服务通过CheckRPC 完成鉴权HTTP 模式本文主角通过普通的 HTTPPOST请求将原始请求属性方法、路径、头部等发送给鉴权服务依据 HTTP 响应状态码判断允许200或拒绝其余状态码。过滤器的核心实现位于 source/extensions/filters/http/ext_authz/ext_authz.cc对应的类声明在 source/extensions/filters/http/ext_authz/ext_authz.h。2.2 请求处理主链路decode → check → onComplete从 ext_authz.cc 可以看到过滤器在decodeHeaders()中发起对外部鉴权服务的调用Http::FilterHeadersStatus Filter::decodeHeaders(Http::RequestHeaderMap headers, bool end_stream) { ... // Initiate a call to the authorization server since we are not disabled. initiateCall(headers); return filter_return_ FilterReturn::StopDecoding ? Http::FilterHeadersStatus::StopAllIterationAndWatermark : Http::FilterHeadersStatus::Continue; }initiateCall()ext_authz.cc#L321-L442会完成 CheckRequest 的组装头部、查询参数、元数据等然后调用客户端的check()方法并把过滤器自身作为RequestCallbacks传入state_ State::Calling; filter_return_ FilterReturn::StopDecoding; // 暂停过滤器链继续迭代 active_client_ client_to_use; initiating_call_ true; client_to_use-check(*this, check_request_, decoder_callbacks_-activeSpan(), decoder_callbacks_-streamInfo()); initiating_call_ false;这里的关键是active_client_成员ext_authz.h#L566 处声明为Filters::Common::ExtAuthz::Client* active_client_{nullptr}它持有的是当前正在服务这一次 in-flight 鉴权请求的客户端裸指针raw pointer。这个裸指针正是本次 UAF 风险的核心关注点。当鉴权服务返回后HTTP 客户端实现会回调过滤器的onComplete()ext_authz.cc#L700-L1160。以拒绝分支为例ext_authz.cc#L1012-L1094case CheckStatus::Denied: { ... // setResponseFlag must be called before sendLocalReply decoder_callbacks_-streamInfo().setResponseFlag( StreamInfo::CoreResponseFlag::UnauthorizedExternalService); decoder_callbacks_-sendLocalReply( response-status_code, response-body, headers response-headers_to_set, callbacks *decoder_callbacks_, this - void { ... }, std::nullopt, Filters::Common::ExtAuthz::ResponseCodeDetails::get().AuthzDenied); break; }sendLocalReply()会直接向下游返回鉴权拒绝的响应例如 403 Forbidden随后过滤器链被终止、流被销毁。三、UAF 漏洞成因剖析HTTP 客户端对象生命周期与裸指针3.1 引用active_client_裸指针的保存与清空在initiateCall()中active_client_ client_to_use被赋值为当前调用使用的客户端对象指针随后在onComplete()的开头ext_authz.cc#L705-L706updateLoggingInfo(response-grpc_status); active_client_ nullptr;以及在onDestroy()ext_authz.cc#L679-L687中void Filter::onDestroy() { if (state_ State::Calling) { state_ State::Complete; if (active_client_ ! nullptr) { active_client_-cancel(); active_client_ nullptr; } } }3.2 UAF 的触发场景修复前从代码结构上可以推断修复前的问题出在客户端对象RawHttpClientImpl的销毁时机上HTTP 模式下的客户端是每流创建的。与 gRPC 模式下复用全局异步客户端不同HTTP 模式的RawHttpClientImpl是伴随当前流创建、由流自身持有生命周期的当鉴权服务返回拒绝过滤器通过sendLocalReply()立即终止了流。此时流的销毁顺序可能导致HTTP 客户端对象先于过滤器回调完成对响应数据的解析而被释放一旦客户端对象被释放而onComplete()回调路径中仍存在对该客户端对象例如其内部的 stream info、上游字节计量器bytes_meter等的访问就会形成典型的UAF悬空指针被解引用。特别地updateLoggingInfo()ext_authz.cc#L637-L673中存在对该指针所指向对象的深入访问// Use the client that actually served this check request for stream info. auto const* stream_info active_client_ ? active_client_-streamInfo() : client_-streamInfo(); if (stream_info nullptr) { return; } const auto bytes_meter stream_info-getUpstreamBytesMeter(); ...如果active_client_指向的对象已被释放active_client_-streamInfo()就是对悬空指针的访问属于典型的释放后使用。同理在拒绝路径上response-headers_to_set等响应对象如果与客户端内部缓冲的生命周期纠缠在一起也可能在流销毁后仍被回调访问。3.3 为什么 HTTP 模式特别容易触发对比两条传输通道的实现gRPC 客户端由grpcAsyncClientManager统一管理以 shared_ptr 形式引用生命周期与集群强绑定流销毁不会导致客户端消失HTTP 客户端RawHttpClientImpl见 source/extensions/filters/common/ext_authz/ext_authz_http_impl.cc是按流创建、随流销毁的临时对象。从 ext_authz.cc#L298-L319 的createPerRouteHttpClient()可以看到每个流都会std::make_uniqueRawHttpClientImpl(...)。因此HTTP 模式下的客户端生命周期与流的销毁时序耦合极深一旦拒绝 立即终止流的路径执行顺序有偏差客户端被提前释放的风险远高于 gRPC 模式。这也解释了为何该 CVE 明确限定于 ext_authz over HTTP。四、修复方案的工程解读从当前仓库代码可以观察到围绕该 UAF 已经形成了一套完整的生命周期防护体系显式状态机管理过滤器通过State { NotStarted, Calling, Complete }枚举ext_authz.h#L553跟踪与鉴权服务的通信阶段。onDestroy()中仅在State::Calling时执行取消逻辑避免在回调已经完成Complete后再次触碰客户端回调入口处立即解绑onComplete()一进入就将active_client_置空确保后续任何对客户端对象的访问都发生在解绑之前杜绝回调执行一半、客户端已释放的窗口流销毁时的取消协议onDestroy()中调用active_client_-cancel()并置空指针保证在流被终止包括被拒绝后终止时挂起的异步回调不会再去触碰已销毁的客户端空指针防御updateLoggingInfo()中对active_client_与stream_info都做了判空即使客户端不可用也不会因悬空指针访问而崩溃。测试方面test/extensions/filters/http/ext_authz/ext_authz_filter_test.cc 中大量用例覆盖了拒绝路径的sendLocalReply期望例如 1754、1793、1831、3206、3252 等行的EXPECT_CALL(decoder_filter_callbacks_, sendLocalReply(...))以及 3927-3929 行展示的先 cancel 再 onDestroy的销毁协议测试从单元测试层面锁定了客户端生命周期的正确管理。这也印证了 test/extensions/filters/http/ext_authz/ext_authz_filter_test.cc#L3927-L3929 中取消与销毁的顺序要求。五、拒绝路径的完整生命周期时序结合源码修复后HTTP 鉴权拒绝请求的完整时序可归纳为decodeHeaders()收到客户端请求过滤器组装CheckRequest并发起 HTTP 调用initiateCall()记录active_client_将filter_return_置为StopDecodingHTTP 鉴权服务返回非 200 状态码RawHttpClientImpl解析响应并回调onComplete()onComplete()立即将active_client_置空并更新日志信息此刻客户端仍存活进入CheckStatus::Denied分支校验响应头、按max_denied_response_body_bytes截断响应体、设置UnauthorizedExternalService响应标志位最后通过sendLocalReply()向下游返回拒绝响应AuthzDenied响应码详情流进入终止流程过滤器链调用onDestroy()此时state_已是Complete不再执行取消操作避免二次触碰已回收的客户端对象。上述第 3 步与第 5 步的配合正是本次修复消除 UAF 的关键回调完成即解绑流销毁不再干预已完成的状态。六、运维与升级建议升级路径修复包含在 CVE-2026-50572 对应的安全版本中所有在生产环境使用HTTP 模式 ext_authz的部署都应在回归测试后尽快升级风险评估本次漏洞仅影响ext_authz配置为http_service的场景gRPC 模式客户端由共享引用管理不受此 CVE 影响验证手段可通过单元测试 test/extensions/filters/http/ext_authz/ext_authz_filter_test.cc 与集成测试 test/extensions/filters/http/ext_authz/ext_authz_integration_test.cc 验证拒绝路径与流销毁的稳定性配置参考HTTP 模式的配置示例可参考 test/extensions/filters/http/ext_authz/ext_authz.yaml过滤器完整配置项定义位于 api/envoy/extensions/filters/http/ext_authz/v3/ext_authz.proto。结语CVE-2026-50572 的修复看似只是一行 changelog背后却是 Envoy 对HTTP 模式下按流创建客户端 拒绝路径立即终止流这一组合场景中对象生命周期严谨性的重新审视。从active_client_的解绑时机、状态机管理到流销毁取消协议source/extensions/filters/http/ext_authz/ext_authz.cc 中的每一处细节都体现了 C 网络代理在异步生命周期管理上的典型工程实践。对于运行 HTTP 模式 ext_authz 的服务网格与 API 网关理解这一修复不仅是安全合规的要求更能帮助你在遇到类似流终止与异步回调竞态问题时快速定位根因。【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考