如何在客户端验证中忽略自签名证书问题
How to ignore Self Signed Certificate issue in client validation
我一直在尝试研究如何禁用用于向授权元数据端点发送请求的 HttpClient 的 SSL 证书验证。我是 运行 本地授权服务器,使用主机名 idp.local.test.com 和 haproxy 作为使用自签名证书的反向代理。
当我在本地测试客户端令牌验证(无自省)时,用于向元数据端点发送 GET 请求的 HttpClient 抛出 SSL 验证错误,因为我使用的是自签名证书。
这是日志的输出:
info: System.Net.Http.HttpClient.OpenIddict.Validation.SystemNetHttp.ClientHandler[100]
Sending HTTP request GET https://idp.local.test.com/.well-known/openid-configuration
System.Net.Http.HttpClient.OpenIddict.Validation.SystemNetHttp.ClientHandler: Information: Sending HTTP request GET https://idp.local.test.com/.well-known/openid-configuration
Loaded '/usr/local/share/dotnet/shared/Microsoft.NETCore.App/3.1.5/System.Diagnostics.StackTrace.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
Loaded '/usr/local/share/dotnet/shared/Microsoft.NETCore.App/3.1.5/System.Reflection.Metadata.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
dbug: OpenIddict.Validation.OpenIddictValidationDispatcher[0]
An exception was thrown by OpenIddict.Validation.SystemNetHttp.OpenIddictValidationSystemNetHttpHandlers+SendHttpRequest`1[[OpenIddict.Validation.OpenIddictValidationEvents+ApplyConfigurationRequestContext, OpenIddict.Validation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=35a561290d20de2f]] while handling the OpenIddict.Validation.OpenIddictValidationEvents+ApplyConfigurationRequestContext event.
System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
at System.Net.Security.SslStream.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, ExceptionDispatchInfo exception)
at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.PartialFrameCallback(AsyncProtocolRequest asyncRequest)
--- End of stack trace from previous location where exception was thrown ---
at System.Net.Security.SslStream.ThrowIfExceptional()
at System.Net.Security.SslStream.InternalEndProcessAuthentication(LazyAsyncResult lazyResult)
at System.Net.Security.SslStream.EndProcessAuthentication(IAsyncResult result)
at System.Net.Security.SslStream.EndAuthenticateAsClient(IAsyncResult asyncResult)
at System.Net.Security.SslStream.<>c.<AuthenticateAsClientAsync>b__65_1(IAsyncResult iar)
at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
这是客户端应用程序中的启动 class:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(options =>
{
options.DefaultScheme = OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme;
});
services.AddOpenIddict()
.AddValidation(options =>
{
// options.Configure(config =>
// {
// config.MetadataAddress = new Uri("/.well-known/openid-configuration");
// });
var section = Configuration.GetSection("OAuth");
var tokenEncryptionKey = section.GetValue<string>("TokenEncryptionKey");
var issuer = section.GetValue<string>("Issuer");
options.SetIssuer(issuer);
options.AddEncryptionKey(new SymmetricSecurityKey(
Convert.FromBase64String(tokenEncryptionKey)
));
options.UseSystemNetHttp();
options.UseAspNetCore();
});
services.AddControllers(options =>
{
options.Filters.Add(typeof(GlobalExceptionFilter));
var requireAuthPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(requireAuthPolicy));
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
这是授权服务器代码:
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders()
.AddPasswordlessLoginTokenProvider()
.AddEmailConfirmationTokenProvider()
.AddPasswordResetTokenProvider();
services.AddOpenIddict()
.AddCore(coreBuilder =>
{
coreBuilder.SetDefaultApplicationEntity<OIDCApplication>()
.UseEntityFrameworkCore()
.UseDbContext<ApplicationDbContext>();
})
.AddServer(serverBuilder =>
{
serverBuilder.RegisterScopes(Scopes.Email, Scopes.Profile, Scopes.Roles, Scopes.OfflineAccess);
serverBuilder.SetAuthorizationEndpointUris("/connect/authorize")
.SetTokenEndpointUris("/connect/token")
.SetConfigurationEndpointUris("/.well-known/openid-configuration")
.SetUserinfoEndpointUris("/connect/userinfo")
.SetIntrospectionEndpointUris("/connect/introspect");
serverBuilder.SetAuthorizationCodeLifetime(TimeSpan.FromMinutes(5));
string issuerHostname = Configuration["IssuerHost"];
serverBuilder.SetIssuer(new Uri($"https://{issuerHostname}"));
serverBuilder.Configure(options =>
{
options.UseSlidingExpiration = true;
});
serverBuilder.AllowAuthorizationCodeFlow()
.AllowRefreshTokenFlow();
serverBuilder.UseAspNetCore()
.EnableAuthorizationEndpointPassthrough()
.EnableTokenEndpointPassthrough()
.EnableUserinfoEndpointPassthrough()
.DisableTransportSecurityRequirement(); // Remove on prod
var tokenEncryptionKey = Configuration.GetValue<string>("TokenEncryptionKey");
serverBuilder.AddEncryptionKey(new SymmetricSecurityKey(
Convert.FromBase64String(tokenEncryptionKey)
));
serverBuilder.AddDevelopmentSigningCertificate();
})
.AddValidation(options =>
{
options.UseLocalServer();
options.UseAspNetCore();
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseHsts();
app.UseMiddleware<Middlewares.LoggingMiddleware>();
app.UseExceptionHandler("/Home/Error");
app.UseStatusCodePagesWithReExecute("/Home/Status", "?code={0}");
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
干杯
将您的自签名证书添加到受信任的证书列表中是正确的做法(这主要取决于您的 OS)。
或者,您可以使用 HttpClientFactory
API 强制 OpenIddict System.Net.Http
集成使用的 HttpClientHandler
忽略服务器证书验证错误:
services.AddHttpClient(typeof(OpenIddictValidationSystemNetHttpOptions).Assembly.GetName().Name)
.ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler
{
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
});
我一直在尝试研究如何禁用用于向授权元数据端点发送请求的 HttpClient 的 SSL 证书验证。我是 运行 本地授权服务器,使用主机名 idp.local.test.com 和 haproxy 作为使用自签名证书的反向代理。
当我在本地测试客户端令牌验证(无自省)时,用于向元数据端点发送 GET 请求的 HttpClient 抛出 SSL 验证错误,因为我使用的是自签名证书。
这是日志的输出:
info: System.Net.Http.HttpClient.OpenIddict.Validation.SystemNetHttp.ClientHandler[100]
Sending HTTP request GET https://idp.local.test.com/.well-known/openid-configuration
System.Net.Http.HttpClient.OpenIddict.Validation.SystemNetHttp.ClientHandler: Information: Sending HTTP request GET https://idp.local.test.com/.well-known/openid-configuration
Loaded '/usr/local/share/dotnet/shared/Microsoft.NETCore.App/3.1.5/System.Diagnostics.StackTrace.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
Loaded '/usr/local/share/dotnet/shared/Microsoft.NETCore.App/3.1.5/System.Reflection.Metadata.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
dbug: OpenIddict.Validation.OpenIddictValidationDispatcher[0]
An exception was thrown by OpenIddict.Validation.SystemNetHttp.OpenIddictValidationSystemNetHttpHandlers+SendHttpRequest`1[[OpenIddict.Validation.OpenIddictValidationEvents+ApplyConfigurationRequestContext, OpenIddict.Validation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=35a561290d20de2f]] while handling the OpenIddict.Validation.OpenIddictValidationEvents+ApplyConfigurationRequestContext event.
System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
at System.Net.Security.SslStream.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, ExceptionDispatchInfo exception)
at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.PartialFrameCallback(AsyncProtocolRequest asyncRequest)
--- End of stack trace from previous location where exception was thrown ---
at System.Net.Security.SslStream.ThrowIfExceptional()
at System.Net.Security.SslStream.InternalEndProcessAuthentication(LazyAsyncResult lazyResult)
at System.Net.Security.SslStream.EndProcessAuthentication(IAsyncResult result)
at System.Net.Security.SslStream.EndAuthenticateAsClient(IAsyncResult asyncResult)
at System.Net.Security.SslStream.<>c.<AuthenticateAsClientAsync>b__65_1(IAsyncResult iar)
at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
这是客户端应用程序中的启动 class:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(options =>
{
options.DefaultScheme = OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme;
});
services.AddOpenIddict()
.AddValidation(options =>
{
// options.Configure(config =>
// {
// config.MetadataAddress = new Uri("/.well-known/openid-configuration");
// });
var section = Configuration.GetSection("OAuth");
var tokenEncryptionKey = section.GetValue<string>("TokenEncryptionKey");
var issuer = section.GetValue<string>("Issuer");
options.SetIssuer(issuer);
options.AddEncryptionKey(new SymmetricSecurityKey(
Convert.FromBase64String(tokenEncryptionKey)
));
options.UseSystemNetHttp();
options.UseAspNetCore();
});
services.AddControllers(options =>
{
options.Filters.Add(typeof(GlobalExceptionFilter));
var requireAuthPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(requireAuthPolicy));
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
这是授权服务器代码:
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders()
.AddPasswordlessLoginTokenProvider()
.AddEmailConfirmationTokenProvider()
.AddPasswordResetTokenProvider();
services.AddOpenIddict()
.AddCore(coreBuilder =>
{
coreBuilder.SetDefaultApplicationEntity<OIDCApplication>()
.UseEntityFrameworkCore()
.UseDbContext<ApplicationDbContext>();
})
.AddServer(serverBuilder =>
{
serverBuilder.RegisterScopes(Scopes.Email, Scopes.Profile, Scopes.Roles, Scopes.OfflineAccess);
serverBuilder.SetAuthorizationEndpointUris("/connect/authorize")
.SetTokenEndpointUris("/connect/token")
.SetConfigurationEndpointUris("/.well-known/openid-configuration")
.SetUserinfoEndpointUris("/connect/userinfo")
.SetIntrospectionEndpointUris("/connect/introspect");
serverBuilder.SetAuthorizationCodeLifetime(TimeSpan.FromMinutes(5));
string issuerHostname = Configuration["IssuerHost"];
serverBuilder.SetIssuer(new Uri($"https://{issuerHostname}"));
serverBuilder.Configure(options =>
{
options.UseSlidingExpiration = true;
});
serverBuilder.AllowAuthorizationCodeFlow()
.AllowRefreshTokenFlow();
serverBuilder.UseAspNetCore()
.EnableAuthorizationEndpointPassthrough()
.EnableTokenEndpointPassthrough()
.EnableUserinfoEndpointPassthrough()
.DisableTransportSecurityRequirement(); // Remove on prod
var tokenEncryptionKey = Configuration.GetValue<string>("TokenEncryptionKey");
serverBuilder.AddEncryptionKey(new SymmetricSecurityKey(
Convert.FromBase64String(tokenEncryptionKey)
));
serverBuilder.AddDevelopmentSigningCertificate();
})
.AddValidation(options =>
{
options.UseLocalServer();
options.UseAspNetCore();
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseHsts();
app.UseMiddleware<Middlewares.LoggingMiddleware>();
app.UseExceptionHandler("/Home/Error");
app.UseStatusCodePagesWithReExecute("/Home/Status", "?code={0}");
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
干杯
将您的自签名证书添加到受信任的证书列表中是正确的做法(这主要取决于您的 OS)。
或者,您可以使用 HttpClientFactory
API 强制 OpenIddict System.Net.Http
集成使用的 HttpClientHandler
忽略服务器证书验证错误:
services.AddHttpClient(typeof(OpenIddictValidationSystemNetHttpOptions).Assembly.GetName().Name)
.ConfigurePrimaryHttpMessageHandler(_ => new HttpClientHandler
{
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
});