
nghttp2_check_authority 详解HTTP/2 中 :authority 与 host 头字段值的字符级校验【免费下载链接】fluent-bitFast and Lightweight Logs, Metrics and Traces processor for Linux, BSD, OSX and Windows项目地址: https://gitcode.com/GitHub_Trending/fl/fluent-bit本篇技术指南聚焦 nghttp2 库的公开 APInghttp2_check_authority讲解它在 HTTP/2 协议中对:authority伪头字段与host头字段值进行合法性校验的语义、RFC 3986 依据、源码实现原理以及它在 nghttp2 头字段解析流程和 Fluent Bit HTTP/2 客户端src/flb_http_client_http2.c中的实际应用。读完本文你将掌握该 API 的精确调用契约、字符级校验规则与语法校验的边界能够正确地在自己的协议处理代码中复用或对照实现这一校验逻辑。函数概览一个面向头字段值的快速合法性检查器nghttp2_check_authority是 nghttp2 暴露的一组字符级校验工具函数中的一员。它的唯一职责是判断一段字节序列是否仅仅由合法字符组成从而可以作为 HTTP/2 请求中的:authority伪头字段值或host头字段值使用。官方 API 文档位于 lib/nghttp2-1.65.0/doc/nghttp2_check_authority.rst函数声明与完整注释位于 lib/nghttp2-1.65.0/lib/includes/nghttp2/nghttp2.h。该工具函数族的同类成员还包括nghttp2_check_header_name、nghttp2_check_header_value、nghttp2_check_path、nghttp2_check_method等它们共同构成 nghttp2 在解析和生成 HTTP/2 头字段时的第一道字符防线。其中nghttp2_check_path的注释nghttp2.h明确说明其允许字符为nghttp2_check_header_value允许的全部字符减去 SPC 和 HT可见这组校验函数在字符集边界上是相互参照、严格设计的。函数签名与语义契约文档给出了完整的函数原型#include nghttp2/nghttp2.h int nghttp2_check_authority(const uint8_t *value, size_t len);参数含义value待校验的字节序列指针预期是:authority或host头字段的值len待校验字节序列的长度字节数返回值若value完全由允许的字符构成返回非零否则返回 0。注意value允许为空len为 0此时循环体不执行、直接返回非零从实现上看空串被视为合法它不包含任何非法字符。从源码实现看lib/nghttp2-1.65.0/lib/nghttp2_helper.c函数本体只有十几行用一个指针遍历[value, value len)区间内的每一个字节逐一查表判断一旦遇到不允许的字符立即返回 0全部通过则返回 1int nghttp2_check_authority(const uint8_t *value, size_t len) { const uint8_t *last; for (last value len; value ! last; value) { if (!VALID_AUTHORITY_CHARS[*value]) { return 0; } } return 1; }这正是字符级校验的典型实现——不含任何状态机、不解析host:port结构、不做 DNS 或语法层面的判断只回答一个问题这些字节是否全部落在允许的字符集合内。校验规则RFC 3986 authority 组件与字符表文档明确说明允许字符集合依据 RFC 3986 第 3.2 节https://tools.ietf.org/html/rfc3986#section-3.2URI 的 authority 组件语法定义。RFC 3986 中 authority 组件的完整语法为authority [ userinfo ] host [ : port ]但文档特别强调了一个关键区别:authority与host字段值并不是完整的 RFC 3986 authority——它们不包含 userinfo 部分RFC 3986 第 3.2.2 节也就是说不应该包含字符。然而出于兼容性考虑nghttp2_check_authority仍然将视为合法字符This function treats as a valid character。这一看似矛盾的设计在头文件注释中有完整阐述:authority或host字段值是实际网络端点标识主机名 可选端口而 RFC 3986 的 authority 语法还允许userinfohost形式在 HTTP/2 头字段场景下 userinfo 不应出现但函数宁可放宽也不拒绝含 的值把这一层的严格性留给上层语义判断。允许字符集合VALID_AUTHORITY_CHARS实际的字符集合固化在 lib/nghttp2-1.65.0/lib/nghttp2_helper.c 的VALID_AUTHORITY_CHARS查找表中注释标明该表由genauthoritychartbl.py脚本生成。对照该表允许的字符包括类别具体字符字母数字A–Z、a–z、0–9标记字符sub-delims!$()*,;其他可见字符%-.:[]_~控制字符/空白全部排除NUL–US、SPC、#/\^{|}DEL 以及全部 0x80–0xFF由此可以看出几条重要的边界允许:和[]这保证了example.com:8080、IPv6 地址字面量[::1]:8080等常见 authority 形式可以通过校验排除/、?、#这些是 URI 中分隔 host/port 与其他组件的保留字符不应出现在 authority 值中排除空格与控制字符SPC、HT、CR、LF 等全部非法这一条在实际安全场景中尤为关键见下文测试用例中的 CRLF 注入防护排除所有非 ASCII 字节0x80–0xFFauthority 值只允许 ASCII 可见字符国际化域名IDN需先转换为 punycode 再传输。语义边界只查字符不查语法文档最后一段用一句话精确划定了本函数的能力边界valueis valid if it merely consists of the allowed characters. In particular, it does not check whethervaluefollows the syntax of authority.即只要逐字节都属于允许字符集函数就返回合法它不检查value是否符合 authority 的语法结构。这意味着以下这类语法上不完整但字符上合法的输入本函数都会放行空字符串len 0缺少主机名的纯端口串如:8080缺少端口的纯主机名如example.org这其实是正常形态含的 userinfo 形式如userexample.org虽然协议层不应出现仅含单个字符的a等。因此nghttp2_check_authority应当被理解为快速字符过滤器而非完整的 authority 解析器它在协议栈中的定位是用极低的开销挡住绝大多数畸形或恶意输入而真正的结构校验、语义校验如 host 是否合法、端口是否越界由上层业务逻辑负责。从源码结构看这也是 nghttp2 设计者的刻意取舍——把是否值得为一段非法值投入解析开销的判断交给更严格的调用场景。在 HTTP/2 头字段处理流程中的角色nghttp2_check_authority的字符表与逻辑在 nghttp2 内部并非孤立存在HTTP 层解析器 lib/nghttp2-1.65.0/lib/nghttp2_http.c 中维护了一份完全相同的VALID_AUTHORITY_CHARS表和同构的静态函数check_authority两份表由同一脚本生成内容一致。静态函数check_authority被nghttp2_http_on_headernghttp2_http.c在解析收到的头字段时调用case NGHTTP2_TOKEN__AUTHORITY: case NGHTTP2_TOKEN_HOST: if (session-server || frame-hd.type NGHTTP2_PUSH_PROMISE) { rv check_authority(nv-value-base, nv-value-len); } else if (...NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) { rv nghttp2_check_header_value(nv-value-base, nv-value-len); } else { rv nghttp2_check_header_value_rfc9113(nv-value-base, nv-value-len); } break;这段代码揭示了几个重要事实服务端与客户端校验策略不同当本端是服务端session-server为真或处理 PUSH_PROMISE 帧时对:authority/host使用严格到字符级的check_authority而当本端是客户端时则退化为按普通头字段值校验nghttp2_check_header_value或 RFC 9113 变体允许前导/尾部空白。这体现了两端信任模型的不同——服务端收到的 authority 决定请求路由目标必须严格客户端收到的值仅作回显参考可以宽松。校验失败的错误分级nghttp2_http_on_header中如果校验失败且字段名以:开头伪头字段如:authority直接返回NGHTTP2_ERR_HTTP_HEADER使连接按协议错误处理若是普通头字段如host则采取宽容策略仅返回NGHTTP2_ERR_IGN_HTTP_HEADER忽略该字段并继续。注释nghttp2_http.c解释得很直白对伪头字段必须严格而对常规头字段要容忍公网上大量存在的非法头部避免因一次校验失败就中断与正常网站的通信。作为公开 API 的意义将同一份校验逻辑同时暴露为公开函数nghttp2_check_authority供库的调用方在生成请求头时预校验与内部静态函数check_authority在接收头字段时校验构成了发送前自检 接收时把关的双向防护。测试用例CRLF 注入防护的实证仓库测试 lib/nghttp2-1.65.0/tests/nghttp2_session_test.c 给出了一个极具代表性的非法 authority 用例const nghttp2_nv badauthority_reqnv[] { MAKE_NV(:scheme, https), MAKE_NV(:method, GET), MAKE_NV(:authority, \x0d\x0alocalhost), MAKE_NV(:path, /)};该用例构造的:authority值为\x0d\x0alocalhost即在主机名前插入了 CR\x0d和 LF\x0a两个控制字符。这正是经典的HTTP 头注入 / 请求走私攻击载荷——如果此类字符被透传可能被下游系统解析为额外的头行。由于VALID_AUTHORITY_CHARS表中 CR、LF 均为 0非法nghttp2_check_authority及其内部对应实现会在第一个字节即返回 0从而在协议层面拦截这类攻击。同文件中同组的badhd_reqnv携带connection头等用例共同覆盖了伪头字段合法性的多种边界可作为回归测试参照。在 Fluent Bit 中的实际集成背景当前仓库将 nghttp2 作为 HTTP/2 协议的底层实现库引入位于 lib/nghttp2-1.65.0Fluent Bit 的 HTTP/2 客户端逻辑位于 src/flb_http_client_http2.c。从源码结构看该文件通过nghttp2_session_callbacks_new、nghttp2_session_client_new等 API 创建客户端会话并以nghttp2_session_send驱动帧发送、通过各回调处理服务端响应——nghttp2_check_authority所在的校验工具族正是这一类会话 API 的配套基础能力。当 Fluent Bit 需要向支持 HTTP/2 的上游如日志采集、指标上报类端点发起请求时nghttp2_check_authority所代表的字符级校验逻辑会在头字段编解码层HPACK之外提供一层额外的输入合法性保障。使用注意事项小结头文件与链接函数声明位于 lib/nghttp2-1.65.0/lib/includes/nghttp2/nghttp2.h实现位于 lib/nghttp2-1.65.0/lib/nghttp2_helper.c使用前包含nghttp2/nghttp2.h即可配合其他校验函数使用它只解决 authority 值的字符合法性字段名的合法性需另行用nghttp2_check_header_name校验:path用nghttp2_check_path普通字段值用nghttp2_check_header_value系列——发送请求前建议对每个头字段按角色选用对应校验函数不要用它替代语法校验若业务要求 authority 必须符合host[:port]的完整语法如必须含主机名、端口必须在合法区间、禁止 userinfo需要在调用本函数之后自行补充结构解析空值与空串len为 0 时函数返回非零视为合法是否允许空 authority 属于上层策略需结合 HTTP/2 规范请求必须携带:authority或host之一自行判断性能特征从实现看为单遍线性扫描O(n)加常数级查表开销极小可安全用于热路径上的每个请求头。综合来看nghttp2_check_authority是一把小而专的字符级过滤器它以 RFC 3986 authority 组件为蓝本、以 256 字节查找表为引擎用近乎零成本的方式完成了 HTTP/2:authority/host值的首道防线校验并在 nghttp2 的接收路径与公开 API 两个层面同时生效是理解 nghttp2 头字段校验体系的最佳切入点之一。【免费下载链接】fluent-bitFast and Lightweight Logs, Metrics and Traces processor for Linux, BSD, OSX and Windows项目地址: https://gitcode.com/GitHub_Trending/fl/fluent-bit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考