ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

RestSharp v113 版本更新深度解析:CVE 安全修复、.NET 10 支持与 Microsoft DI 集成

RestSharp v113 版本更新深度解析:CVE 安全修复、.NET 10 支持与 Microsoft DI 集成 后端API设计【免费下载链接】RestSharpSimple REST and HTTP API Client for .NET项目地址https://gitcode.com/gh_mirrors/re/RestSharp点击查看免费下载本指南以 RestSharp 当前主版本的官方变更日志docs/versioned_docs/version-v113/changelog.md为骨架逐条剖析 v112.0 → v113.0 之间的关键改动包括针对 CVE-2024-45302 的 CRLF 头注入安全修复、.NET 9 / .NET 10 目标框架支持、System.Text.Json v10 升级、全新RestSharp.Extensions.DependencyInjection包以及 404 响应语义与AddUrlSegment同名参数行为的变更。读完本文你将准确理解每个版本变化的底层实现与升级影响并能在实际项目中正确配置新选项、使用 DI 集成避免踩中破坏性变更的坑。版本脉络概览变更日志按时间线覆盖了三个小版本核心脉络如下版本主题关键内容v112.0安全修复修复 [CVE-2024-45302]Header 值中禁止包含CRLFv112.1安全修复跟进将\t制表符从 Header 禁止字符列表中移除v113.0功能与新特性.NET 9/10 支持、System.Text.Json v10、Microsoft DI 集成、404 语义调整、新错误处理选项、AddUrlSegment覆盖语义其中 v112.0 与 v112.1 属于同一安全修复的“补丁 微调”v113.0 则是功能层面的主版本更新。更早版本的发布说明不在本文档范围内可查看 RestSharp GitHub 仓库的 Releases 页面变更日志第 9 行注明。各主版本之间的差异在官网对应版本的文档中有详细记录。CVE-2024-45302Header 值中的 CRLF 注入修复v112.0 / v112.1漏洞背景与危害v112.0 的核心改动是一项安全修复Header 值中不再允许包含CRLF即\r\n字符。CRLF 是 HTTP 头与头之间、头与正文之间的分隔符。如果开发者将用户输入直接拼入 Header 值攻击者可以通过注入\r\n伪造新的请求头、请求正文甚至整条请求即 HTTP 请求走私 / Header 注入攻击。源码层实现在仓库源码中这一限制由 HeaderParameter.cs 实现。构造HeaderParameter时会对名称与值做双重校验static string EnsureValidHeaderValue(string name, string value, bool encode) { CheckAndThrowsForInvalidHost(name, value); return EnsureValidHeaderString(GetValue(Ensure.NotNull(value, nameof(value)), encode), value); } static string EnsureValidHeaderString(string value, string type) !IsInvalidHeaderString(value) ? value : throw new ArgumentException($Invalid character found in header {type}: {value}); static bool IsInvalidHeaderString(string stringValue) { for (var i 0; i stringValue.Length; i) { switch (stringValue[i]) { case \r: case \n: return true; } } return false; }可以看到HeaderParameter.cs#L39-L63非法字符检查目前只拦截\r和\n两个字符命中即抛出ArgumentException异常消息为Invalid character found in header {type}: {value}。v112.1 的跟进移除\t限制v112.0 发布后团队在 v112.1 中做了一个细微调整将制表符\t从禁止字符列表中移除。这也是为什么当前源码的IsInvalidHeaderString中只有\r与\n两个 case ——\t在部分合法业务场景如携带时间戳或格式化文本的 Header中是可接受的过度限制会造成误伤。如果你在旧版本中曾因 Header 含\t报错升级到 v112.1 及以上后该问题消失。测试佐证仓库测试 RequestHeaderTests.cs#L178-L182 直接覆盖了该安全场景[Fact] public void Should_not_allow_CRLF_in_header_value() { var request new RestRequest(); Assert.ThrowsArgumentException(() request.AddHeader( name, 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头、空行与伪造请求行。RestSharp 会在参数构造阶段直接抛出ArgumentException从源头阻断注入。对使用者的影响升级到 v112.0 后任何包含\r或\n的 Header 值都会在AddHeader/AddOrUpdateParameter阶段抛异常请勿在 Header 值中拼接换行数据若确需传输包含换行的内容极少数场景应在业务层先行编码例如 Base64而不是直接塞进 Header该校验同时作用于 Header 名称与值且Host头还有额外的格式校验见 HeaderParameter.cs#L67-L74。v113.0 核心更新一.NET 9 / .NET 10 与 System.Text.Json v10v113.0 的框架支持范围扩大到.NET 9 与 .NET 10同时将System.Text.Json 统一升级到 v10覆盖所有目标框架。在仓库的 Directory.Packages.props集中版本管理中可以看到框架相关的版本分组PropertyGroup LabelPackage versions for .NET 10 Condition$(TargetFramework) net10.0 MicrosoftTestHostVer10.0.0/MicrosoftTestHostVer SystemTextJsonVer10.0.0/SystemTextJsonVer /PropertyGroup PropertyGroup LabelPackage versions for .NET 9 Condition$(TargetFramework) net9.0 MicrosoftTestHostVer9.0.10/MicrosoftTestHostVer /PropertyGroup PropertyGroup LabelPackage versions for pre-.NET 10 Condition$(TargetFramework) ! net10.0 SystemTextJsonVer10.0.0/SystemTextJsonVer /PropertyGroup注意SystemTextJsonVer在 net10.0 与其它目标框架下均为10.0.0这印证了变更日志中“System.Text.Json v10 覆盖所有目标框架”的描述。而在 RestSharp.csproj 中只有老框架net471、net48、netstandard2.0需要显式引入System.Text.Json包ItemGroup Condition$(TargetFramework) net471 PackageReference IncludeSystem.Text.Json / /ItemGroup ItemGroup Condition$(TargetFramework) net48 PackageReference IncludeSystem.Text.Json / /ItemGroup ItemGroup Condition$(TargetFramework) netstandard2.0 PackageReference IncludeSystem.Text.Json / /ItemGroup升级建议如果你的项目目标是net8.0或更高版本并直接使用 RestSharp 的 JSON 序列化默认SystemTextJsonSerializer见 Serializers/Json 目录升级到 v113 后将统一使用 System.Text.Json v10 的行为与 API请注意 v10 相对旧版在序列化细节如默认大小写策略、新 API 与性能改进上的差异。v113.0 核心更新二RestSharp.Extensions.DependencyInjection 新包v113.0 引入了一个全新 NuGet 包RestSharp.Extensions.DependencyInjection它让 RestSharp 原生接入 Microsoft 依赖注入容器与IHttpClientFactory。相关源码位于 src/RestSharp.Extensions.DependencyInjection 目录完整的 DI 用法文档见 docs/versioned_docs/version-v113/usage/di.md。设计动机与收益通过该包将IRestClient以 transient 生命周期注册进容器底层 HTTP 客户端与消息处理器HttpMessageHandler完全交由IHttpClientFactory管理。文档列出的收益包括集中管理为不同逻辑客户端如名为github的客户端提供统一的命名、注册与配置位置同时可注册一个面向常规访问的默认客户端连接池与生命周期自动管理由工厂统一管理底层HttpMessageHandler的池化与回收规避手动管理 RestClient 生命周期时常见的 DNS 问题handler 长期不释放导致 DNS 缓存失效。注册默认客户端在 ASP.NET Core 的Program.cs中调用AddRestClient()即可注册IHttpClientFactory、IRestClientFactory与IRestClientvar builder WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddRestClient();随后即可将IRestClient注入任意服务public class GetReposModel(IRestClient client) : PageModel { public IEnumerableGitHubBranch? GitHubBranches { get; set; } public async Task OnGet() { var request new RestRequest(https://api.github.com/repos/RestSharp/RestSharp/branches); var response await client.ExecuteGetAsyncIEnumerableGitHubBranch(request); if (response.IsSuccessful) { GitHubBranches response.Data; } } }默认客户端也支持通过扩展方法传入 base URL 或完整自定义选项// 指定 base URL builder.Services.AddRestClient(new Uri(https://api.github.com)); // 提供自定义选项 var options new RestClientOptions(https://api.github.com) { Timeout TimeSpan.FromSeconds(5) }; builder.Services.AddRestClient(options);注册命名客户端当应用需要多个配置不同的客户端例如同时调用 GitHub 与 Twilio API时使用命名客户端并通过IRestClientFactory按名获取var options new RestClientOptions(https://api.github.com) { Timeout TimeSpan.FromSeconds(5) }; builder.Services.AddRestClient(github, options);public class GetReposModel(IRestClientFactory factory) : PageModel { public IEnumerableGitHubBranch? GitHubBranches { get; set; } public async Task OnGet() { var request new RestRequest(/repos/RestSharp/RestSharp/branches); var client factory.CreateClient(github); var response await client.ExecuteGetAsyncIEnumerableGitHubBranch(request); if (response.IsSuccessful) { GitHubBranches response.Data; } } }最灵活的注册方式允许在注册时同时配置选项与序列化器builder.Services.AddRestClient( my-client, options { options.BaseUrl new Uri(https://api.github.com); options.Timeout TimeSpan.FromSeconds(1); options.Authenticator new GitHubAuthenticator(builder.Configuration[GitHub:ApiToken]); }, serialization serialization.UseNewtonsoftJson() );底层实现链路从源码看注册逻辑集中在 ServiceCollectionExtensions.cs内部通过services.AddHttpClient(name)来自Microsoft.Extensions.Http见 Directory.Packages.props#L19为每个命名客户端创建受工厂管理的HttpClient并配置主HttpMessageHandler默认客户端的固定名称是常量DefaultRestClient见 Constants.cs无参AddRestClient()实际委托给该名称的注册默认客户端以 transient 方式注册IRestClient从IHttpClientFactory取出HttpClient后包装为RestClient命名客户端的配置选项委托与序列化委托通过IOptionsMonitorRestClientConfigOptions存储键为{name}$RestClientConstants.cs#L20按名创建时DefaultRestClientFactory.cs 使用IHttpClientFactory.CreateClient(name)与IOptionsMonitor中取出的配置共同构造RestClient。v113.0 核心更新三404 响应使 IsSuccessful 变为 false变更日志第 26 行明确了新语义当响应状态码为 404Not Found时IsSuccessful现在被置为false。这与响应构建逻辑直接相关。在 RestResponseBase.cs#L71-L77 中public bool IsSuccessStatusCode { get; set; } public bool IsSuccessful IsSuccessStatusCode ResponseStatus ResponseStatus.Completed;IsSuccessful由两个条件共同决定HTTP 状态码是否成功2xxResponseStatus是否为Completed。而ResponseStatus的默认计算逻辑定义在 RestClientOptions.cs#L61-L64public CalculateResponseStatus CalculateResponseStatus { get; set; } httpResponse httpResponse.IsSuccessStatusCode || httpResponse.StatusCode HttpStatusCode.NotFound ? ResponseStatus.Completed : ResponseStatus.Error;要点解读404 的ResponseStatus仍为Completed表示请求流程本身完成不是网络/传输错误但 404 不是IsSuccessStatusCode因此组合后IsSuccessful为false这一调整修正了此前 404 在IsSuccessful上表现暧昧的问题让“业务上未找到资源”与“请求成功完成”在语义上彻底分离。ResponseStatus始终只是“完成度”指标与 API 错误处理无关此点也与 docs/versioned_docs/version-v113/advanced/error-handling.md 中的错误处理说明一致。实践影响如果你的旧代码依赖“404 时IsSuccessful true”来判断资源不存在升级后必须改为检查response.StatusCode HttpStatusCode.NotFound。v113.0 核心更新四新增错误处理选项变更日志第 27 行引入了一个向后兼容的新选项当ErrorWhenUnsuccessfulStatusCode设为false时非成功状态码对应的错误消息与异常将不再附加到响应对象上该选项默认为true。选项命名与源码对应需要特别说明变更日志中该选项写作ErrorWhenUnsuccessfulStatusCode而当前仓库源码中对应的可配置属性名为SetErrorExceptionOnUnsuccessfulStatusCode定义于 RestClientOptions.cs#L237-L241/// summary /// When set to false, the client doesnt set the ErrorException property for responses with unsuccessful status codes. /// Default is true. /// /summary public bool SetErrorExceptionOnUnsuccessfulStatusCode { get; set; } true;不同发布版本间的命名可能略有差异使用前请以你所引用版本的实际 API 为准。底层行为该开关直接控制ErrorException的生成。核心实现在 HttpResponseExtensions.cs#L21-L28public static Exception? MaybeException(this HttpResponseMessage httpResponse, bool throwOnUnsuccessfulStatusCode) httpResponse.IsSuccessStatusCode || !throwOnUnsuccessfulStatusCode ? null #if NET : new HttpRequestException($Request failed with status code {httpResponse.StatusCode}, null, httpResponse.StatusCode); #else : new HttpRequestException($Request failed with status code {httpResponse.StatusCode}); #endif响应装配时RestResponse.cs#L66ErrorException httpResponse.MaybeException(options.SetErrorExceptionOnUnsuccessfulStatusCode)异步执行路径同样遵循该开关见 RestClient.Async.cs#L52。使用示例var options new RestClientOptions(https://api.github.com) { // 设为 false 后非成功状态码不会生成 HttpRequestException 附加到响应 SetErrorExceptionOnUnsuccessfulStatusCode false }; var client new RestClient(options); var response await client.ExecuteGetAsyncMyModel(new RestRequest(/not-found)); // response.ErrorException 为 null需要自行检查 response.StatusCode / response.IsSuccessful适用场景当你的业务将 4xx/5xx 视为“正常返回的响应数据”而非“异常”时例如调用网关、风控服务状态码本身就是业务结果关闭该选项可以避免为每个非 2xx 响应分配异常对象既减少噪音又降低 GC 压力。默认保持true是为了向后兼容旧行为。v113.0 核心更新五AddUrlSegment 同名参数“后者覆盖前者”变更日志第 28 行当AddUrlSegment以相同名称被多次调用时将使用最后一次传入的值。实现机制AddUrlSegment的实现位于 RestRequestExtensions.Url.cs#L31-L32public RestRequest AddUrlSegment(string name, string? value, bool encode true) request.AddOrUpdateParameter(new UrlSegmentParameter(name, value, encode));它并不直接追加参数而是委托给AddOrUpdateParameterRestRequestExtensions.cs#L113-L114public RestRequest AddOrUpdateParameter(Parameter parameter) request.RemoveParameter(parameter.Name, parameter.Type).AddParameter(parameter);语义非常明确先移除同名同类型的旧参数再添加新参数因此最后一次调用的值生效。使用示例var request new RestRequest(users/{id}/posts/{id}) // 同一个占位符 {id} 出现两次 .AddUrlSegment(id, 123) // 第一次id 123 .AddUrlSegment(id, 456); // 第二次覆盖为 456最终生效值 // 结果 URL/users/456/posts/456升级注意此前版本中同名段参数可能叠加导致行为不确定v113 明确了“后写覆盖先写”的规则。若你的代码依赖旧的叠加行为升级后请显式改为不同名称的占位符如{id}与{postId}。升级检查清单综合以上变更从 v112 升级到 v113.0或从更早版本直接升级时建议逐项核对检查项说明Header 值安全确保业务代码不会向 Header 传入含\r/\n的值v112.0 起抛异常含\t的值在 v112.1 起合法目标框架v113 新增 .NET 9 / .NET 10 目标老框架net471/net48/netstandard2.0仍受支持System.Text.Json所有目标框架统一为 v10注意序列化行为差异404 语义IsSuccessful对 404 现在为false请改用StatusCode判断资源不存在错误处理新选项默认在非成功状态码时附加HttpRequestExceptionSetErrorExceptionOnUnsuccessfulStatusCode默认true如不需要可显式关闭URL 段参数AddUrlSegment同名多次调用以后一次为准DI 集成新包RestSharp.Extensions.DependencyInjection提供默认/命名客户端注册替代手写工厂代码如需深入各特性的用法细节可继续阅读仓库内对应文档DI 集成指南、错误处理指南以及本版本文档首页 intro.md变更日志原文见 docs/versioned_docs/version-v113/changelog.md。赞分享后端API设计【免费下载链接】RestSharpSimple REST and HTTP API Client for .NET项目地址https://gitcode.com/gh_mirrors/re/RestSharp点击查看免费下载相关推荐Node.js v19.6.1 安全版本深度解析三个 CVE 修复、OpenSSL 3.0.8 升级与 undici 更新Node.js v19.6.1 安全版本深度解析三个 CVE 修复、OpenSSL 3.0.8 升级与 undici 更新 导读 Node.js 19.6.前端文档kOps 1.7 版本深度解读Manifest 重写、Calico Pod CIDR 修复与 CVE-2017-14491 安全更新kOps 1.7 版本深度解读Manifest 重写、Calico Pod CIDR 修复与 CVE 2017 14491 安全更新 导读 本文基于仓库中的云原生集群管理运维IaCXAML Standard迁移指南现有项目如何升级到统一标准XAML Standard迁移指南现有项目如何升级到统一标准 XAML Standard 是微软推出的一套推动XAML方言对齐的原则性标准旨在帮助开发者更轻上一篇EmotiVoice长文本合成终极指南突破500字限制的3种有效策略下一篇终极指南如何将闲置电视盒子变身高性能Armbian服务器创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表