ARTICLE DETAIL

资讯详情

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

Envoy CVE-2019-15225 与 CVE-2019-15226 安全事件复盘:正则匹配栈溢出与 HeaderMap O(n²) 拒绝服务漏洞的根因与修复

Envoy CVE-2019-15225 与 CVE-2019-15226 安全事件复盘:正则匹配栈溢出与 HeaderMap O(n²) 拒绝服务漏洞的根因与修复 Envoy CVE-2019-15225 与 CVE-2019-15226 安全事件复盘正则匹配栈溢出与 HeaderMap O(n²) 拒绝服务漏洞的根因与修复【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy本文基于 Envoy 官方安全事后分析文档 cve-2019-15225.md其关联页面 cve-2019-15226.md 指向同一份复盘撰写并对照当前仓库源码深入剖析 2019 年随 1.11.2 安全版本一同发布的两个漏洞——CVE-2019-15225路由正则匹配栈内存耗尽崩溃与 CVE-2019-15226HeaderMap 逐头校验导致的 O(n²) 拒绝服务——的根因、检测过程、修复方案与经验教训。读完本文你将理解 Envoy 为何引入safe_regexRE2作为安全正则引擎、为何将HeaderMapImpl::byteSize()从 O(n) 迭代改写为 O(1) 缓存计数以及如何在当前版本中配置max_headers_count、max_request_headers_kb与 RE2 程序大小上限来加固生产环境。事件概览漏洞基本信息项目内容漏洞编号CVE-2019-15225正则匹配栈耗尽、CVE-2019-15226HeaderMap O(n²) DoS事件周期2019-07-25 至 2019-10-10报告人 / 发现方式CVE-2019-15225 由用户 Seikun Kambashi 公开报告CVE-2019-15226 由 OSS-Fuzz / ClusterFuzz 模糊测试超时报障发现影响范围所有使用路由正则匹配的 Envoy 版本CVE-2019-15225所有 Envoy 发行版HTTP/2 流量CVE-2019-15226修复版本Envoy 1.11.2 安全版本2019-09-18 公告2019-10-08 推送事后追踪 Issueissue/8519、issue/8520附随 issue8567、8875、8898、8901事件经过2019 年 7 月 25 日一名 Envoy 用户在 GitHub Issue issue/7728 中公开报告了路由解析阶段正则匹配导致崩溃的问题。Envoy 安全团队随后确认该问题可被利用发起拒绝服务DoS攻击并转入公开安全版本发布流程修复以公开 PR pull/7878 合入 master计划随 1.11.2 安全版本发布。而在 1.11.1 安全版本发布后不久模糊测试器恰好发现了另一个问题CVE-2019-15226。由于 CVE-2019-15225 的修复尚在进行中安全团队决定将两份修复合并到同一个 1.11.2 安全版本中发布。这是 Envoy 安全版本历史上第一次包含一个已公开披露、且修复已合入 master 的漏洞CVE-2019-15225——1.11.2 同时携带了该修复的回移植补丁以及 CVE-2019-15226 的补丁。按 SECURITY.md 中既定的流程候选补丁于 2019-09-24 提供给发行商预留了两周的测试与准备时间。根因分析CVE-2019-15225递归正则匹配导致的栈内存耗尽CVE-2019-15225 的根因是使用了递归算法实现的正则匹配引擎。Envoy 的 HTTP 路由器允许为路由配置正则表达式用于匹配传入 HTTP 请求的 Header 值在当时的实现中这些正则表达式由 libstdc 的std::regex提供支持。std::regex基于回溯backtracking实现在匹配超长输入时可能消耗大量栈内存并导致进程异常终止。文档明确指出带有*或量词的正则表达式尤其危险当匹配的 Header 值达到16 KB 或更大时即可能触发崩溃。攻击者只需构造一个携带超长 Header或超长 URI正如 issue/7728 中的崩溃场景的 HTTP 请求就能利用该缺陷打垮 Envoy 进程。CVE-2019-15226逐 Header 校验引发的 O(n²) 性能退化CVE-2019-15226 源于对HeaderMap的过度迭代每次添加一个 Header 时都会执行一次耗时的 Header 总大小校验。HTTP 解析库 http_parserHTTP/1与 nghttp2HTTP/2自身都有最大请求头大小的内部限制而 Envoy 的 HTTP/2 codec 原本针对硬编码的 63 KB 最大头大小做校验——这个值刚好略低于 nghttp2 的默认最大头长度。由于该校验在每一个 Header 被加入时都会执行一次整体性能退化为 O(n²)。值得一提的是当时推进「将该限制可配置化」的工作issue/5626在 Envoy 的 HTTP/1 codec 中也引入了同样的问题——逐 Header 字段做校验复刻了原始 HTTP/2 codec 的问题模式。也就是说HTTP/1 与 HTTP/2 两条路径在修复前都存在这一 O(n²) 缺陷。从当前仓库源码可以印证这一修复后的状态HTTP/2 codec 在 codec_impl.cc 中仅在累积大小检查点执行if (headers_size max_headers_kb_ * 1024)并将限制同步给 nghttp2见 codec_impl.cc 的max_header_list_bytes与max_header_field_size而非逐 Header 触发完整迭代。修复方案正则匹配引入安全正则引擎 RE2 与 safe_regex为消除std::regex回溯导致的栈消耗Envoy 1.11.2 在面向用户的路径中弃用std::regex引入了一个新的安全正则匹配器safe regex matcher支持显式配置正则引擎。发布时该引擎限定为 Google 的RE2——它实现了std::regex语言特性的一个安全子集在线性时间内完成匹配不依赖回溯并限制内存使用上限从算法层面杜绝了此类栈耗尽攻击。原有的std::regex引擎进入弃用过渡期以便用户迁移到安全引擎。RE2 的「程序大小」program size是对编译后正则复杂度的粗略估算。Envoy 1.11.2 起允许配置程序大小上限超过该阈值的正则将编译失败。在 api/envoy/type/matcher/v3/regex.proto 中GoogleRE2消息通过google.protobuf.UInt32Value max_program_size暴露该配置并在注释中说明其默认行为由 runtime 键控制re2.max_program_size.error_level默认值为 100超过即拒绝编译re2.max_program_size.warn_level默认不设不告警。对应的 runtime 实现位于 runtime_features.cc同时 Envoy 会通过直方图统计re2.program_size指标便于观测线上正则的复杂度分布。一个现代 Envoy 配置中安全正则路由的典型写法如下RegexMatcher显式选择google_re2引擎替代旧的regex字段routes: - match: prefix: / route: cluster: service_cluster对应头匹配的安全正则示意match: headers: - name: :path safe_regex_match: google_re2: {} regex: ^/api/v[0-9]/.*HeaderMapbyteSize() O(1) 化与可配置的最大 Header 数CVE-2019-15226 的修复包含两部分将HeaderMapImpl::byteSize()重写为 O(1)不再每次迭代整个HeaderMap计算字节数而是为HeaderMapImpl新增cached_byte_size_成员在 Header 条目加入时同步更新该缓存值并直接返回。当前源码中的实现即位于 header_map_impl.haddSize(uint64_t size)负责累加cached_byte_size_初始为 0byteSize()直接返回缓存值。为访问日志场景引入可配置的最大 Header 数限制访问日志中若配置了大量 Header formatter 且请求本身携带大量 Header对HeaderMap的迭代次数同样会放大为 DoS 向量因此修复新增了对最大 Header 数的可配置上限。在 api/envoy/config/core/v3/protocol.proto 中HttpProtocolOptions提供了max_headers_count默认 100可通过 runtime 键envoy.reloadable_features.max_request_headers_count与max_response_headers_count覆盖下游请求超过该值HTTP/1.x 返回431、HTTP/2 触发 stream reset上游响应超限则返回502。max_request_headers_kb则控制请求头总大小默认 60 KiBHTTP/1 响应头默认 80 KiB。这两个配置共同把「头数量」与「头总大小」都纳入了显式可控的防护面。检测与发现过程CVE-2019-15225公开 Issue 报告但模糊测试器存在逻辑缺陷CVE-2019-15225 由 Seikun Kambashi 在公开 GitHub Issueissue/7728中报告配置了正则匹配器的路由收到携带超长 URI 的请求即崩溃。复盘文档特别指出Envoy 的route_fuzz_test模糊测试路由解析与 Header 收尾本应能捕获该崩溃——它以RouteConfiguration和一组 Header 为输入用给定配置路由携带输入 Header 的请求。按理说模糊器很容易生成「通配符匹配器 超长 Header 串」的组合但该模糊测试自身存在一个逻辑错误它忽略了输入的路径 Header并一律将其设为默认值 /导致永远不会测试到超长 URIOOM 或崩溃自然无法被检出。该模糊测试在 pull/8653 中修复并补充了针对该 CVE 的复现用例。CVE-2019-15226ClusterFuzz 超时报障CVE-2019-15226 最初也是经模糊器发现的2019-08-09h1_capture_direct_fuzz_test报告了超时OSS-Fuzz issue 16325embargo 下。性能剖析揭示HeaderMapImpl::byteSize()对 Header 数量是 O(n) 的而它在 HTTP/1.1 与 HTTP/2 两个 codec 中对每一个 Header 都会被调用。Envoy 无状态的 HTTP/2 头模糊器request_header_fuzz_test、response_header_fuzz_test每秒执行数比前者高 10 倍但每次测试用例只覆盖一个 HEADER 帧且使用 nghttp2 默认的最大头帧大小16 KB帧太小无法将 O(n²) 放大到足以产生超时因此未能更早暴露问题。这一对比凸显了模糊测试输入规模帧大小、Header 数量对 DoS 类缺陷检出能力的决定性影响。经验教训做得好的方面CVE-2019-15226 在模糊器报出超时后被快速定位确认修复直截了当且局部化风险可控安全版本按时发布遵循了 SECURITY.md 制定的流程。暴露的问题分支与权限管理为修复补丁建立分支花了近一周源于对 GitHub Security Advisories 权限模型与 CI 集成的支持存在分歧期间envoy-setec分支一度对所有 Envoy 贡献者可读GitHub 团队权限重组还一度导致无法为 Issue 指派成员。分支保护缺失修复团队成员可向envoy-setec分支直接推送1.11.2 甚至可直接推到 master需要分支保护来确保 CI 把关合并。发布就绪标准发布前一天只有手工补丁集没有反映它们的 envoy-setec 分支端到端通过复盘结论是「未通过完整 CI 之前不应认为发布就绪」且应建立提供 yes/no 判断的预提交检查。模糊测试盲区路由解析模糊器因逻辑错误漏掉了正则漏洞更高效率的请求/响应模糊器因只模糊单帧 HEADER、且 HTTP/2 默认最大帧 16 KB也无法更早捕获该漏洞。发行商沟通有发行商反馈「直到今早的说明才知道 safe_regex正在打补丁切换到 safe_regex」因此后续给发行商的安全说明应注明是否需要用法变更。版本耦合的代价CVE-2019-15225 与 CVE-2019-15226 的修复耦合发布起初出于发布开销的考虑是合理的但当 HeaderMap 修复的发布日一再延后时意味着一个已知漏洞已在 master 修复、却未出现在任何已发布版本中——暴露窗口被拉长。幸运之处master 与 v1.12.2 发布分支虽未在私有修复分支上完整通过 CI但仅出现少量 CI 失败bazel.compile_time_options未造成进一步延误。时间线美国太平洋时间日期事件2019-07-25[CVE-2019-15225] issue/7728 报告路由正则匹配超长 URI 崩溃2019-08-09[CVE-2019-15226] ClusterFuzz 在 embargo 下报告 OSS-Fuzz issue 163252019-08-13[CVE-2019-15226] 安全邮件组启动 HeaderMap DoS 分析排查同类 O(n²) 代码路径2019-08-19为两个 CVE 申请 CVE ID2019-08-20配置 envoy-setec 分支权限与 CI 权限2019-08-21[CVE-2019-15226] 私有安全仓库共享草稿修复 PR后续三周评审迭代2019-08-23[CVE-2019-15225] 修复 PRpull/7878公开2019-09-18[CVE-2019-15226] 向发行商邮件列表分享 CVE 摘要2019-09-19确认所有 Envoy 发行版对 HTTP/2 流量均受影响更新 CVE2019-09-24向发行商分享候选修复补丁2019-10-07基于已评审工作手工组装补丁集2019-10-08补丁微调使暂存分支通过 CI11:20 推送 v1.11.2发布时更新 CVE2019-10-10提交后续追踪 Issue 8567对当前版本运维的启示虽然这两个 CVE 已随 1.11.2 修复但其教训直接塑造了今天 Envoy 的安全配置面建议在生产环境中落实路由/头匹配一律使用safe_regex_matchgoogle_re2不要回退到基于std::regex的旧regex字段已弃用。善用 RE2 程序大小上限通过max_program_size或 runtime 键re2.max_program_size.error_level默认 100/re2.max_program_size.warn_level限制正则复杂度并关注re2.program_size直方图指标防止上线后出现超高复杂度正则。显式配置头部防护上限在HttpConnectionManager与 Cluster 的HttpProtocolOptions中按需设置max_headers_count默认 100与max_request_headers_kb默认 60 KiB借助envoy.reloadable_features.max_request_headers_count等 runtime 键做灰度。参考官方漏洞追踪与配置文档相关配置细节可继续查阅 regex.proto 与 protocol.proto安全发布流程见 SECURITY.md完整复盘原文见 cve-2019-15225.md。【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表