RestSharp v112 安全更新全解析:CVE-2024-45302 与 Header 值 CRLF 注入防护
【免费下载链接】RestSharpSimple REST and HTTP API Client for .NET项目地址: https://gitcode.com/gh_mirrors/re/RestSharp
导读
本文围绕 RestSharp v112 系列(v112.0 与 v112.1)的 changelog 展开,深入剖析本次针对 CVE-2024-45302 的安全修复:为何 HTTP Header 值中的CRLF字符是致命漏洞,RestSharp 如何在源码层拦截恶意输入,以及 v112.1 为何又对禁止字符列表做了"减法"(移除\t)。读完本文,你将理解 Header 注入/请求走私类攻击的成因、RestSharp 的防护实现与测试验证方式,并掌握升级到 v112 后如何正确适配AddHeader系列 API 的行为变化。
本文以 版本化文档 v112 changelog 为主体,结合仓库内 HeaderParameter.cs 源码与 RequestHeaderTests.cs 测试用例进行印证。
一、v112 系列改了什么:两个小版本一次安全修复
v112 的 changelog 内容非常精炼,只有两条,但每一条都对应一次安全层面的关键变更:
v112.0:针对 CVE-2024-45302 的安全修复
Security fix for CVE-2024-45302. Header values cannot contain
CRLF.
v112.0 的核心动作是:RestSharp 从此拒绝在 Header 值中包含CRLF(即\r\n,回车 + 换行)的请求。这属于一次强制性的安全加固——不是警告、不是自动转义,而是直接抛异常拒绝构造这样的请求。
v112.1:对禁止字符列表的修正
Follow up on v112.0 security fix: remove
\tfrom the list of forbidden characters in headers.
v112.1 是紧随其后的修正:v112.0 在收紧校验时,曾将制表符\t一并列入禁止字符;v112.1 将其移出禁止列表,恢复\t在 Header 值中的合法性。
值得注意的是,仓库中的版本化文档为 v112 保留了独立的文档快照(见 docs/versions.json 中的v112条目与 version-v112 文档目录),说明该版本仍被官方文档体系维护,其安全修复也完整同步进了后续版本(v113 及以上的 changelog 同样收录了这两条记录,例如 version-v113 changelog)。
二、漏洞背景:为什么 Header 值里的 CRLF 是危险的
2.1 HTTP 报文结构决定了 CRLF 的特殊地位
在 HTTP/1.x 协议中,报文由CRLF(\r\n)作为分隔符:
- 请求行与请求头之间、每个 Header 字段之间、Header 与 Body 之间,全部依赖
\r\n进行切分; - 一个 Header 字段的终止,恰好就是它后面的第一个
CRLF。
这就带来一个经典问题:如果应用程序把用户可控的输入直接拼接到 Header 值中,且不校验其中是否包含CRLF,攻击者就能利用\r\n提前"终结"当前字段,并伪造出新的 Header 字段甚至伪请求体。
2.2 攻击场景:响应头注入与请求走私
结合仓库测试用例中展示的 payload(见 RequestHeaderTests.cs),一次典型的注入尝试长这样:
test\r\nUser-Agent: injected header!\r\n\r\nGET /smuggled HTTP/1.1\r\nHost: insert.some.site.here攻击者把一个看似正常的 Header 值,通过嵌入\r\n扩展成:
- 一个额外的
User-Agent: injected header!字段(响应头注入 / Header 注入); - 一段以空行(
\r\n\r\n)结尾、接着伪造的GET /smuggled HTTP/1.1请求行(HTTP 请求走私的雏形)。
这类漏洞在真实世界中可能被利用于:向响应中注入恶意内容(XSS 变体)、绕过代理/缓存、污染下游请求,甚至将攻击请求"走私"给后端服务器。CVE-2024-45302 正是 RestSharp 被报告的这一类问题。
2.3 修复的直观意义
修复后,上述 payload 无法通过 RestSharp 的 API 进入 HTTP 管线——AddHeader直接抛出ArgumentException,从源头切断注入面,而不是依赖HttpClient或下游服务器去兜底。
三、源码级验证:Header 校验到底在哪里发生
3.1 校验入口:HeaderParameter 构造函数
所有 Header 相关的请求扩展方法最终都会创建 HeaderParameter,校验逻辑就集中在它的构造函数与静态方法中:
public HeaderParameter(string name, string value, bool encode = false) : base( EnsureValidHeaderString(Ensure.NotEmptyString(name, nameof(name)), "name"), EnsureValidHeaderValue(name, value, encode), ParameterType.HttpHeader, false ) { }这里同时校验了两类输入:
- Header 名称:不能为空字符串(
NotEmptyString),且同样要经过EnsureValidHeaderString的字符级检查; - Header 值:先做
Host字段专项校验(CheckAndThrowsForInvalidHost),再经EnsureValidHeaderString做字符级检查,最后通过Ensure.NotNull拒绝null值。
3.2 核心判定:IsInvalidHeaderString 只禁 CR 与 LF
当前仓库中 IsInvalidHeaderString 的实现 是 v112.1 之后的最终状态:
static bool IsInvalidHeaderString(string stringValue) { for (var i = 0; i < stringValue.Length; i++) { switch (stringValue[i]) { case '\r': case '\n': return true; } } return false; }两个值得注意的细节:
- 只针对
\r(CR,0x0D)与\n(LF,0x0A)判定为非法,与 v112.0/v112.1 的安全修复目标完全一致; \t(HTAB,0x09)不在禁止列表中,这正是 v112.1 移除\t之后的状态——代码里只保留了对 CRLF 的拦截。
一旦检测到非法字符,EnsureValidHeaderString 会抛出:
static string EnsureValidHeaderString(string value, string type) => !IsInvalidHeaderString(value) ? value : throw new ArgumentException($"Invalid character found in header {type}: {value}");即ArgumentException("Invalid character found in header value: ...")。
3.3 为什么 v112.1 要移除 \t
这与 HTTP 规范有关:在 RFC 7230 等规范中,Header 字段值(field-value)允许包含可见字符以及HTAB(水平制表符)与SP(空格)作为字段内空白。\t本身是合法字符,很多既有应用(例如配置格式中缩进、多值拼接)会依赖它。v112.0 修复时采取的"宁严勿宽"策略把\t一并禁掉,虽然更安全,但会误伤合法用例;v112.1 随即将其移出禁止列表,把防护范围精确收敛到真正危险的 CR/LF 上。从当前源码看,最终落地的策略正是这种"精确拦截"。
四、测试如何验证修复:从注入 payload 到异常断言
安全修复是否生效,最终要靠测试兜底。仓库在 RequestHeaderTests.cs 中专门为本次修复补充了测试用例:
[Fact] public void Should_not_allow_CRLF_in_header_value() { var request = new RestRequest(); Assert.Throws<ArgumentException>(() => request.AddHeader("name", "test\r\nUser-Agent: injected header!\r\n\r\nGET /smuggled HTTP/1.1\r\nHost: insert.some.site.here")); }这个测试的要点:
- 构造攻击载荷:复刻真实的 Header 注入 payload(注入
User-Agent头 + 伪造请求行); - 走公开 API:通过
RestRequest.AddHeader触发校验链路,验证的不是某个内部方法,而是用户实际调用的入口; - 断言异常类型:
ArgumentException被抛出,证明恶意输入在请求发出前就被拦截。
与它同文件的还有一组输入校验测试,共同勾勒出 v112 对 Header 输入的完整防护矩阵(RequestHeaderTests.cs):
| 测试 | 输入 | 期望异常 |
|---|---|---|
Should_not_allow_null_header_value | 值为null | ArgumentNullException(参数名value) |
Should_not_allow_null_header_name | 名为null | ArgumentNullException(参数名name) |
Should_not_allow_empty_header_name | 名为空字符串 | ArgumentException(参数名name) |
Should_not_allow_CRLF_in_header_value | 值含\r\n注入载荷 | ArgumentException |
五、对开发者的影响:升级到 v112 需要知道什么
5.1 API 层面:行为从"容忍"变为"拒绝"
本次修复没有新增 API,而是收紧既有 API 的输入校验。所有创建HeaderParameter的入口都会受影响,主要包括 RestRequestExtensions.Headers.cs 中的:
AddHeader(name, value)/AddHeader(name, values[])/AddHeader<T>(name, value, culture);AddOrUpdateHeader(name, value)/AddOrUpdateHeader<T>(...);AddHeaders(...)/AddOrUpdateHeaders(...)批量方法。
由于这些方法最终都汇聚到HeaderParameter构造,因此单一入口校验意味着任何路径下的非法值都会被一致拦截。
5.2 代码适配建议
如果你的业务代码中 Header 值可能来自用户输入(如文件名、URL 参数、日志字段等),升级后请检查:
- 输入预处理:在调用
AddHeader前剔除或转义\r、\n,例如对换行做替换或直接拒绝; - 异常处理:
ArgumentException属于同步抛出的编程错误类异常,建议在组装请求时统一捕获并转换为业务错误提示,避免请求构造失败被当作网络错误误判; - 合法用例回归:确认没有依赖
\t在 Header 值中的代码——v112.1 之后\t已恢复合法,但如果你的代码基于 v112.0 的严格列表做了过滤,可以放宽到只处理 CR/LF; - 不要绕过校验:不要在构建
HeaderParameter之后再手工修改Parameter.Value或直接操作HttpRequestMessage.Headers绕过防护——那会重新打开注入面(集成测试也验证了拦截器内直接Headers.Add的行为,见 HttpHeadersTests.cs)。
5.3 服务端配合
客户端校验是第一道防线,但服务端仍应继续对收到的 Header 做 RFC 合规校验(拒绝含 CR/LF 的字段),形成纵深防御。RestSharp 的修复解决的是"客户端不再可能发出这类请求",而非替代服务端的安全策略。
六、如何确认你的环境已应用修复
判断所使用版本是否包含该修复,可以从两个维度核对:
- 版本号:确认依赖锁定在
112.0.0及以上(112.0.0已包含 CRLF 拦截,112.1.0起\t恢复合法); - 源码特征:检查
HeaderParameter中IsInvalidHeaderString的switch分支是否仅包含\r与\n两个case——若包含\t分支则处于 v112.0 的严格状态,若完全没有 CR/LF 检查则属于修复前的旧版本。
仓库中同时保留了 v112 与 v113+ 的版本化文档(docs/versioned_docs/version-v112、docs/versioned_docs/version-v113),两份 changelog 均收录了本次修复,方便对照各版本的文档基线。
结语
RestSharp v112 的这次更新虽然只涉及两个小版本、两行 changelog,背后却是完整的"漏洞发现 → 紧急修复 → 策略修正 → 测试固化"闭环:v112.0 用最严格的字符黑名单切断 CRLF 注入面,v112.1 在安全与兼容之间校准刻度(恢复\t),源码 HeaderParameter.cs 给出精确到字符级的实现,RequestHeaderTests.cs 用真实攻击载荷锁定回归。对开发者而言,理解这条修复链路,既是升级到 v112+ 的适配指南,也是一堂关于"HTTP Header 输入校验"的实战安全课。
【免费下载链接】RestSharpSimple REST and HTTP API Client for .NET项目地址: https://gitcode.com/gh_mirrors/re/RestSharp
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考