From e2561a127e45d7af51d0e90b4eabb93c2f1a9496 Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Tue, 27 May 2025 11:48:11 +0200 Subject: [PATCH 1/6] try without TLS --- scenarios/rejection.benchmarks.yml | 30 ++++++++++++++++ src/BenchmarksApps/TLS/HttpSys/Program.cs | 26 ++++++++++---- .../TLS/HttpSys/appsettings.Development.json | 4 ++- src/BenchmarksApps/TLS/Kestrel/Program.cs | 36 ++++++++++++------- .../TLS/Kestrel/appsettings.Development.json | 3 +- 5 files changed, 78 insertions(+), 21 deletions(-) diff --git a/scenarios/rejection.benchmarks.yml b/scenarios/rejection.benchmarks.yml index e2abc5ec4..fd15847f2 100644 --- a/scenarios/rejection.benchmarks.yml +++ b/scenarios/rejection.benchmarks.yml @@ -92,6 +92,21 @@ scenarios: customHeaders: - "Host: google.com" + httpsys-hostheader-mismatch-notls: + application: + job: httpSysServer + variables: + httpSysUrlPrefix: "http://testserver:{{serverPort}}" + httpOnly: true + load: + job: wrk + variables: + path: /hello-world + connections: 32 + serverScheme: http + customHeaders: + - "Host: google.com" + # Kestrel kestrel-encoded-url: @@ -131,3 +146,18 @@ scenarios: serverScheme: https customHeaders: - "Host: google.com" + + kestrel-hostheader-mismatch-notls: + application: + job: kestrelServer + variables: + enableHostHeaderValidation: true + httpOnly: true + load: + job: wrk + variables: + path: /hello-world + connections: 32 + serverScheme: http + customHeaders: + - "Host: google.com" \ No newline at end of file diff --git a/src/BenchmarksApps/TLS/HttpSys/Program.cs b/src/BenchmarksApps/TLS/HttpSys/Program.cs index 53b724781..a5db31e41 100644 --- a/src/BenchmarksApps/TLS/HttpSys/Program.cs +++ b/src/BenchmarksApps/TLS/HttpSys/Program.cs @@ -14,6 +14,9 @@ var certPublicKeyLength = certPublicKeySpecified ? certPublicKeyConfig : 2048; var urlPrefix = builder.Configuration["httpSysUrlPrefix"]; +// for investigation purposes you can disable https, but the point of TLS apps is to measure TLS scenarios +var httpOnly = bool.TryParse(builder.Configuration["httpOnly"], out var httpOnlyConfig) && httpOnlyConfig; + // endpoints var listeningEndpoints = builder.Configuration["urls"] ?? "https://localhost:5000/"; var httpsIpPort = listeningEndpoints.Split(";").First(x => x.Contains("https")).Replace("https://", ""); @@ -23,15 +26,18 @@ var statsEnabled = bool.TryParse(builder.Configuration["statsEnabled"], out var connectionStatsEnabledConfig) && connectionStatsEnabledConfig; var logRequestDetails = bool.TryParse(builder.Configuration["logRequestDetails"], out var logRequestDetailsConfig) && logRequestDetailsConfig; -var sslCertConfiguration = NetshConfigurator.PreConfigureNetsh( +if (!httpOnly) +{ + var sslCertConfiguration = NetshConfigurator.PreConfigureNetsh( httpsIpPort, certPublicKeyLength: certPublicKeyLength, clientCertNegotiation: mTlsEnabled ? NetShFlag.Enable : NetShFlag.Disabled, disablesessionid: NetShFlag.Enable, enableSessionTicket: NetShFlag.Disabled); -// because app shutdown is on a timeout, we need to prepare the reset (pre-generate certificate) -NetshConfigurator.PrepareResetNetsh(httpsIpPort, certPublicKeyLength: 4096); + // because app shutdown is on a timeout, we need to prepare the reset (pre-generate certificate) + NetshConfigurator.PrepareResetNetsh(httpsIpPort, certPublicKeyLength: 4096); +} #pragma warning disable CA1416 // Can be launched only on Windows (HttpSys) builder.WebHost.UseHttpSys(options => @@ -126,7 +132,10 @@ await app.StartAsync(); -NetshConfigurator.LogCurrentSslCertBinding(httpsIpPort); +if (!httpOnly) +{ + NetshConfigurator.LogCurrentSslCertBinding(httpsIpPort); +} Console.WriteLine("Application Info:"); if (mTlsEnabled) @@ -148,6 +157,9 @@ await app.WaitForShutdownAsync(); Console.WriteLine("Application stopped."); -Console.WriteLine("Starting netsh rollback configuration..."); -NetshConfigurator.ResetNetshConfiguration(httpsIpPort); -Console.WriteLine($"Reset netsh (ipport={httpsIpPort}) completed."); \ No newline at end of file +if (!httpOnly) +{ + Console.WriteLine("Starting netsh rollback configuration..."); + NetshConfigurator.ResetNetshConfiguration(httpsIpPort); + Console.WriteLine($"Reset netsh (ipport={httpsIpPort}) completed."); +} \ No newline at end of file diff --git a/src/BenchmarksApps/TLS/HttpSys/appsettings.Development.json b/src/BenchmarksApps/TLS/HttpSys/appsettings.Development.json index a7a6b1a26..da8d3c3bd 100644 --- a/src/BenchmarksApps/TLS/HttpSys/appsettings.Development.json +++ b/src/BenchmarksApps/TLS/HttpSys/appsettings.Development.json @@ -9,5 +9,7 @@ "httpSysLogs": "true", "tlsRenegotiation": "false", "certValidationConsoleEnabled": "false", - "httpSysUrlPrefix": "https://testserver:5000/" + //"httpSysUrlPrefix": "https://testserver:5000/", + "httpSysUrlPrefix": "http://localhost:5001/", + "httpOnly": "true" } diff --git a/src/BenchmarksApps/TLS/Kestrel/Program.cs b/src/BenchmarksApps/TLS/Kestrel/Program.cs index 73bc3608e..c8eff392b 100644 --- a/src/BenchmarksApps/TLS/Kestrel/Program.cs +++ b/src/BenchmarksApps/TLS/Kestrel/Program.cs @@ -22,6 +22,9 @@ var certPublicKeyLength = certPublicKeySpecified ? certPublicKeyConfig : 2048; var enableHostHeaderValidation = bool.TryParse(builder.Configuration["enableHostHeaderValidation"], out var enableHostHeaderValidationConfig) && enableHostHeaderValidationConfig; +// for investigation purposes you can disable https, but the point of TLS apps is to measure TLS scenarios +var httpOnly = bool.TryParse(builder.Configuration["httpOnly"], out var httpOnlyConfig) && httpOnlyConfig; + // endpoints var listeningEndpoints = builder.Configuration["urls"] ?? "https://localhost:5000/"; var supportedTlsVersions = ParseSslProtocols(builder.Configuration["tlsProtocols"]); @@ -71,6 +74,22 @@ void ConfigureListen(KestrelServerOptions serverOptions, IConfigurationRoot conf serverOptions.Listen(endpoint, listenOptions => { + var protocol = config["protocol"] ?? ""; + if (protocol.Equals("h2", StringComparison.OrdinalIgnoreCase)) + { + listenOptions.Protocols = HttpProtocols.Http1AndHttp2; + } + else if (protocol.Equals("h2c", StringComparison.OrdinalIgnoreCase)) + { + listenOptions.Protocols = HttpProtocols.Http2; + } + + if (httpOnly) + { + // all TLS related settings should be below + return; + } + var certificatePath = Path.Combine("certificates", $"testCert-{certPublicKeyLength}.pfx"); Console.WriteLine($"Using certificate: {certificatePath}"); @@ -107,16 +126,6 @@ void ConfigureListen(KestrelServerOptions serverOptions, IConfigurationRoot conf options.ClientCertificateValidation = AllowAnyCertificateValidationWithLogging; } }); - - var protocol = config["protocol"] ?? ""; - if (protocol.Equals("h2", StringComparison.OrdinalIgnoreCase)) - { - listenOptions.Protocols = HttpProtocols.Http1AndHttp2; - } - else if (protocol.Equals("h2c", StringComparison.OrdinalIgnoreCase)) - { - listenOptions.Protocols = HttpProtocols.Http2; - } }); } }); @@ -204,7 +213,11 @@ bool AllowAnyCertificateValidationWithLogging(X509Certificate2 certificate, X509 await app.StartAsync(); Console.WriteLine("Application Info:"); -LogOpenSSLVersion(); +if (!httpOnly) +{ + LogOpenSSLVersion(); + Console.WriteLine($"\tsupported TLS versions: {supportedTlsVersions}"); +} if (mTlsEnabled) { Console.WriteLine($"\tmTLS is enabled (client cert is required)"); @@ -221,7 +234,6 @@ bool AllowAnyCertificateValidationWithLogging(X509Certificate2 certificate, X509 { Console.WriteLine($"\tenabled logging stats to console"); } -Console.WriteLine($"\tsupported TLS versions: {supportedTlsVersions}"); Console.WriteLine($"\tlistening endpoints: {listeningEndpoints}"); Console.WriteLine("--------------------------------"); diff --git a/src/BenchmarksApps/TLS/Kestrel/appsettings.Development.json b/src/BenchmarksApps/TLS/Kestrel/appsettings.Development.json index 5305412c5..5eef435ad 100644 --- a/src/BenchmarksApps/TLS/Kestrel/appsettings.Development.json +++ b/src/BenchmarksApps/TLS/Kestrel/appsettings.Development.json @@ -8,5 +8,6 @@ "mTLS": "false", "tlsRenegotiation": "false", "certValidationConsoleEnabled": "false", - "enableHostHeaderValidation": "false" + "enableHostHeaderValidation": "true", + "httpOnly": "true" } From 34fef3c85cd25ae727eca7c5e9f77d353e87e302 Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Tue, 27 May 2025 11:55:04 +0200 Subject: [PATCH 2/6] http scheme for server --- scenarios/rejection.benchmarks.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/scenarios/rejection.benchmarks.yml b/scenarios/rejection.benchmarks.yml index fd15847f2..33c195639 100644 --- a/scenarios/rejection.benchmarks.yml +++ b/scenarios/rejection.benchmarks.yml @@ -20,6 +20,7 @@ jobs: project: src/BenchmarksApps/TLS/HttpSys/HttpSys.csproj readyStateText: Application started. variables: + serverScheme: https # behavioral settings mTLS: false # enables settings on http.sys to negotiate client cert on connections tlsRenegotiation: false # enables client cert validation @@ -30,7 +31,7 @@ jobs: httpSysLogs: false statsEnabled: false logRequestDetails: false - arguments: "--urls https://{{serverAddress}}:{{serverPort}} --mTLS {{mTLS}} --certValidationConsoleEnabled {{certValidationConsoleEnabled}} --statsEnabled {{statsEnabled}} --tlsRenegotiation {{tlsRenegotiation}} --httpSysLogs {{httpSysLogs}} --logRequestDetails {{logRequestDetails}} --httpSysUrlPrefix {{httpSysUrlPrefix}}" + arguments: "--urls {{serverScheme}}://{{serverAddress}}:{{serverPort}} --mTLS {{mTLS}} --certValidationConsoleEnabled {{certValidationConsoleEnabled}} --statsEnabled {{statsEnabled}} --tlsRenegotiation {{tlsRenegotiation}} --httpSysLogs {{httpSysLogs}} --logRequestDetails {{logRequestDetails}} --httpSysUrlPrefix {{httpSysUrlPrefix}}" kestrelServer: source: @@ -39,6 +40,7 @@ jobs: project: src/BenchmarksApps/TLS/Kestrel/Kestrel.csproj readyStateText: Application started. variables: + serverScheme: https # behavioral settings mTLS: false tlsRenegotiation: false @@ -49,7 +51,7 @@ jobs: certValidationConsoleEnabled: false statsEnabled: false logRequestDetails: false - arguments: "--urls https://{{serverAddress}}:{{serverPort}} --mTLS {{mTLS}} --certValidationConsoleEnabled {{certValidationConsoleEnabled}} --tlsProtocols {{tlsProtocols}} --statsEnabled {{statsEnabled}} --tlsRenegotiation {{tlsRenegotiation}} --logRequestDetails {{logRequestDetails}} --enableHostHeaderValidation {{enableHostHeaderValidation}}" + arguments: "--urls {{serverScheme}}://{{serverAddress}}:{{serverPort}} --mTLS {{mTLS}} --certValidationConsoleEnabled {{certValidationConsoleEnabled}} --tlsProtocols {{tlsProtocols}} --statsEnabled {{statsEnabled}} --tlsRenegotiation {{tlsRenegotiation}} --logRequestDetails {{logRequestDetails}} --enableHostHeaderValidation {{enableHostHeaderValidation}}" scenarios: @@ -152,6 +154,7 @@ scenarios: job: kestrelServer variables: enableHostHeaderValidation: true + serverScheme: http httpOnly: true load: job: wrk From 5ef39c2fcc7fbe22285617a25cfcbd2f095af4ee Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Tue, 27 May 2025 11:58:26 +0200 Subject: [PATCH 3/6] httpsys httponly --- scenarios/rejection.benchmarks.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/scenarios/rejection.benchmarks.yml b/scenarios/rejection.benchmarks.yml index 33c195639..37fe9f62d 100644 --- a/scenarios/rejection.benchmarks.yml +++ b/scenarios/rejection.benchmarks.yml @@ -99,6 +99,7 @@ scenarios: job: httpSysServer variables: httpSysUrlPrefix: "http://testserver:{{serverPort}}" + serverScheme: http httpOnly: true load: job: wrk From aacf55242e186daaa089523c0decddbcef790603 Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Tue, 27 May 2025 12:02:52 +0200 Subject: [PATCH 4/6] fix NRE --- src/BenchmarksApps/TLS/HttpSys/Program.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/BenchmarksApps/TLS/HttpSys/Program.cs b/src/BenchmarksApps/TLS/HttpSys/Program.cs index a5db31e41..072df425d 100644 --- a/src/BenchmarksApps/TLS/HttpSys/Program.cs +++ b/src/BenchmarksApps/TLS/HttpSys/Program.cs @@ -19,7 +19,7 @@ // endpoints var listeningEndpoints = builder.Configuration["urls"] ?? "https://localhost:5000/"; -var httpsIpPort = listeningEndpoints.Split(";").First(x => x.Contains("https")).Replace("https://", ""); +var httpsIpPort = listeningEndpoints.Split(";").FirstOrDefault(x => x.Contains("https"))?.Replace("https://", ""); // debug var writeCertValidationEventsToConsole = bool.TryParse(builder.Configuration["certValidationConsoleEnabled"], out var certValidationConsoleEnabled) && certValidationConsoleEnabled; @@ -29,7 +29,7 @@ if (!httpOnly) { var sslCertConfiguration = NetshConfigurator.PreConfigureNetsh( - httpsIpPort, + httpsIpPort!, certPublicKeyLength: certPublicKeyLength, clientCertNegotiation: mTlsEnabled ? NetShFlag.Enable : NetShFlag.Disabled, disablesessionid: NetShFlag.Enable, @@ -134,7 +134,7 @@ if (!httpOnly) { - NetshConfigurator.LogCurrentSslCertBinding(httpsIpPort); + NetshConfigurator.LogCurrentSslCertBinding(httpsIpPort!); } Console.WriteLine("Application Info:"); From bbf473520a50ae3c272e8e2efd7682298cceb414 Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Tue, 27 May 2025 12:10:52 +0200 Subject: [PATCH 5/6] dont rely on a separate flag --- scenarios/rejection.benchmarks.yml | 2 -- src/BenchmarksApps/TLS/HttpSys/Program.cs | 8 +++++--- src/BenchmarksApps/TLS/Kestrel/Program.cs | 20 ++++++++++++++++---- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/scenarios/rejection.benchmarks.yml b/scenarios/rejection.benchmarks.yml index 37fe9f62d..1ac214755 100644 --- a/scenarios/rejection.benchmarks.yml +++ b/scenarios/rejection.benchmarks.yml @@ -100,7 +100,6 @@ scenarios: variables: httpSysUrlPrefix: "http://testserver:{{serverPort}}" serverScheme: http - httpOnly: true load: job: wrk variables: @@ -156,7 +155,6 @@ scenarios: variables: enableHostHeaderValidation: true serverScheme: http - httpOnly: true load: job: wrk variables: diff --git a/src/BenchmarksApps/TLS/HttpSys/Program.cs b/src/BenchmarksApps/TLS/HttpSys/Program.cs index 072df425d..95c526f1f 100644 --- a/src/BenchmarksApps/TLS/HttpSys/Program.cs +++ b/src/BenchmarksApps/TLS/HttpSys/Program.cs @@ -14,12 +14,14 @@ var certPublicKeyLength = certPublicKeySpecified ? certPublicKeyConfig : 2048; var urlPrefix = builder.Configuration["httpSysUrlPrefix"]; -// for investigation purposes you can disable https, but the point of TLS apps is to measure TLS scenarios -var httpOnly = bool.TryParse(builder.Configuration["httpOnly"], out var httpOnlyConfig) && httpOnlyConfig; - // endpoints var listeningEndpoints = builder.Configuration["urls"] ?? "https://localhost:5000/"; var httpsIpPort = listeningEndpoints.Split(";").FirstOrDefault(x => x.Contains("https"))?.Replace("https://", ""); +var httpOnly = httpsIpPort is null; // in case TLS is disabled. Only for debug purposes - this app is designed to measure TLS scenario +if (httpOnly) +{ + Console.WriteLine("[Note] Server scheme is HTTP, not HTTPS."); +} // debug var writeCertValidationEventsToConsole = bool.TryParse(builder.Configuration["certValidationConsoleEnabled"], out var certValidationConsoleEnabled) && certValidationConsoleEnabled; diff --git a/src/BenchmarksApps/TLS/Kestrel/Program.cs b/src/BenchmarksApps/TLS/Kestrel/Program.cs index c8eff392b..dcaebfca2 100644 --- a/src/BenchmarksApps/TLS/Kestrel/Program.cs +++ b/src/BenchmarksApps/TLS/Kestrel/Program.cs @@ -21,13 +21,25 @@ var certPublicKeySpecified = int.TryParse(builder.Configuration["certPublicKeyLength"], out var certPublicKeyConfig); var certPublicKeyLength = certPublicKeySpecified ? certPublicKeyConfig : 2048; var enableHostHeaderValidation = bool.TryParse(builder.Configuration["enableHostHeaderValidation"], out var enableHostHeaderValidationConfig) && enableHostHeaderValidationConfig; - -// for investigation purposes you can disable https, but the point of TLS apps is to measure TLS scenarios -var httpOnly = bool.TryParse(builder.Configuration["httpOnly"], out var httpOnlyConfig) && httpOnlyConfig; +var supportedTlsVersions = ParseSslProtocols(builder.Configuration["tlsProtocols"]); // endpoints var listeningEndpoints = builder.Configuration["urls"] ?? "https://localhost:5000/"; -var supportedTlsVersions = ParseSslProtocols(builder.Configuration["tlsProtocols"]); + +// determine if listening is expected only on HTTP scheme +var httpOnly = true; +foreach (var endpoint in listeningEndpoints.Split([';'], StringSplitOptions.RemoveEmptyEntries)) +{ + var urlPrefix = UrlPrefix.Create(endpoint); + if (urlPrefix.Scheme == "https") + { + httpOnly = false; + } +} +if (httpOnly) +{ + Console.WriteLine("[Note] Server scheme is HTTP, not HTTPS."); +} // debug var writeCertValidationEventsToConsole = bool.TryParse(builder.Configuration["certValidationConsoleEnabled"], out var certValidationConsoleEnabled) && certValidationConsoleEnabled; From f43036a85e485919e56347aa5fdce4d13fd7390b Mon Sep 17 00:00:00 2001 From: Dmitrii Korolev Date: Tue, 27 May 2025 12:17:43 +0200 Subject: [PATCH 6/6] settings to init --- src/BenchmarksApps/TLS/HttpSys/appsettings.Development.json | 5 ++--- src/BenchmarksApps/TLS/Kestrel/appsettings.Development.json | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/BenchmarksApps/TLS/HttpSys/appsettings.Development.json b/src/BenchmarksApps/TLS/HttpSys/appsettings.Development.json index da8d3c3bd..f0e97d0ba 100644 --- a/src/BenchmarksApps/TLS/HttpSys/appsettings.Development.json +++ b/src/BenchmarksApps/TLS/HttpSys/appsettings.Development.json @@ -9,7 +9,6 @@ "httpSysLogs": "true", "tlsRenegotiation": "false", "certValidationConsoleEnabled": "false", - //"httpSysUrlPrefix": "https://testserver:5000/", - "httpSysUrlPrefix": "http://localhost:5001/", - "httpOnly": "true" + // "httpSysUrlPrefix": "https://testserver:5000/", + "httpOnly": "false" } diff --git a/src/BenchmarksApps/TLS/Kestrel/appsettings.Development.json b/src/BenchmarksApps/TLS/Kestrel/appsettings.Development.json index 5eef435ad..4334d3431 100644 --- a/src/BenchmarksApps/TLS/Kestrel/appsettings.Development.json +++ b/src/BenchmarksApps/TLS/Kestrel/appsettings.Development.json @@ -8,6 +8,6 @@ "mTLS": "false", "tlsRenegotiation": "false", "certValidationConsoleEnabled": "false", - "enableHostHeaderValidation": "true", - "httpOnly": "true" + "enableHostHeaderValidation": "false", + "httpOnly": "false" }