HTTPS, Certificates & Transport Security
15 questions found
How do you enforce that all HTTP requests to an ASP.NET Core application are redirected to HTTPS?
Beginner
The UseHttpsRedirection() middleware, registered early in the pipeline, automatically issues a redirect (307 by default) to the HTTPS equivalent of any incoming HTTP request's URL -- combined with UseHsts() in production (which instructs browsers to never even attempt plain HTTP after the first successful HTTPS visit), this ensures the application is never served meaningfully over unencrypted HTTP.
var app = builder.Build();
if (!app.Environment.IsDevelopment()) {
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Real-world example
A banking API redirects every plain HTTP request to its HTTPS equivalent automatically, ensuring that even a user who mistakenly types http:// instead of https:// in their browser is immediately and transparently redirected to the secure version.
Common follow-ups: What HTTP status code does the redirect use, and why does that choice matter for caching?;What's the difference between HTTPS redirection and HSTS, and why do you need both?
Hosting Models: Kestrel
IIS & Reverse Proxies;Security Headers
Antiforgery & CSRF Protection
What is HSTS (HTTP Strict Transport Security), and how does UseHsts() in ASP.NET Core implement it?
Intermediate
HSTS is a response header (Strict-Transport-Security) instructing browsers to automatically convert any future request to the site into HTTPS internally, without even attempting a plain HTTP connection first -- this closes the vulnerability window that plain HTTP-to-HTTPS redirection alone leaves open (the very first request in a session is still sent over unencrypted HTTP before the redirect happens), since after the first HSTS-header response, the browser enforces HTTPS-only on its own for the specified duration (max-age).
builder.Services.AddHsts(options => {
options.MaxAge = TimeSpan.FromDays(365);
options.IncludeSubDomains = true;
options.Preload = true;
});
var app = builder.Build();
if (!app.Environment.IsDevelopment()) {
app.UseHsts(); // adds Strict-Transport-Security header to responses
}
Real-world example
A financial services site configures HSTS with a full year max-age and IncludeSubDomains, ensuring that once a user's browser has visited the site once over HTTPS, it will never again attempt a plain HTTP connection to that domain or any of its subdomains for the following year, even if a user explicitly types http://.
Common follow-ups: What is HSTS preloading, and how does submitting to the browser preload list eliminate the first-visit vulnerability window entirely?;What risk does a very long max-age create if you ever need to revert to HTTP temporarily?
Security Headers
Antiforgery & CSRF Protection;Hosting Models: Kestrel
IIS & Reverse Proxies
How would you configure Kestrel to use a specific X.509 certificate for HTTPS, and what are the different ways to supply that certificate (file-based, certificate store, Azure Key Vault)?
Advanced
Kestrel's HTTPS configuration accepts a certificate via several sources: a PFX file with a password (common for development/simple deployments), the Windows/Linux certificate store referenced by thumbprint (common in enterprise/IIS-integrated scenarios), or a cloud secret manager like Azure Key Vault (via a certificate provider integration, avoiding storing certificate files or passwords directly in configuration) -- production deployments increasingly favor Key Vault or a managed certificate service to avoid manual certificate file management and rotation.
// File-based (appsettings.json)
"Kestrel": { "Endpoints": { "Https": { "Url": "https://*:5001", "Certificate": { "Path": "cert.pfx", "Password": "secret" } } } }
// Certificate store by thumbprint (code)
builder.WebHost.ConfigureKestrel(options => {
options.ListenAnyIP(5001, o => o.UseHttps(StoreName.My, "A1B2C3...", StoreLocation.LocalMachine));
});
// Azure Key Vault integration
builder.Configuration.AddAzureKeyVault(vaultUri, credential);
Real-world example
An enterprise deployment loads its production TLS certificate directly from Azure Key Vault at startup, with automatic rotation handled by Key Vault's own certificate lifecycle management, avoiding the operational burden of manually renewing and redeploying PFX certificate files before each expiration.
Common follow-ups: How do you implement zero-downtime certificate rotation without restarting the Kestrel process?;What's the security risk of storing a PFX password directly in appsettings.json versus a secret manager?
Hosting Models: Kestrel
IIS & Reverse Proxies;Configuration & Options Pattern
What is a self-signed certificate, and why is the ASP.NET Core development HTTPS certificate (dotnet dev-certs) not suitable for production use?
Intermediate
A self-signed certificate is one not issued by a trusted Certificate Authority (CA), meaning browsers and other clients don't inherently trust it and will show security warnings unless the certificate is manually trusted on each machine -- the dotnet dev-certs tool generates exactly this kind of certificate for local development convenience (installed into the local trust store so your own machine's browser doesn't warn), but it must never be used in production since external users' browsers/devices have no way to trust it, and it's fundamentally not designed for that purpose (short-lived, tied to the local machine).
# Generate and trust a local development HTTPS certificate
dotnet dev-certs https --trust
# For production, obtain a certificate from a real, trusted CA instead
# (e.g. via Let's Encrypt, DigiCert, or your organization's internal CA)
Real-world example
A developer testing locally uses dotnet dev-certs https --trust to get a working HTTPS localhost environment without browser warnings, but the production deployment uses a properly CA-issued certificate obtained through the company's certificate management process, never the dev certificate.
Common follow-ups: What happens if a dev certificate is accidentally used in a staging or production environment?;How does certificate trust actually work at the browser/OS level (the chain of trust)?
Hosting Models: Kestrel
IIS & Reverse Proxies;Configuration & Options Pattern
How would you implement mutual TLS (mTLS) authentication in ASP.NET Core, where the server also validates a client-presented certificate?
Advanced
Mutual TLS requires configuring Kestrel to request and validate a client certificate during the TLS handshake (ClientCertificateMode.RequireCertificate), then using the Certificate Authentication middleware (AddCertificate()) to translate the validated client certificate into a ClaimsPrincipal usable by the standard authentication/authorization system -- commonly used for service-to-service authentication in zero-trust architectures or B2B API integrations where both sides need cryptographic proof of identity, not just the server.
builder.WebHost.ConfigureKestrel(options => {
options.ConfigureHttpsDefaults(o => o.ClientCertificateMode = ClientCertificateMode.RequireCertificate);
});
builder.Services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate(options => {
options.AllowedCertificateTypes = CertificateTypes.Chained;
options.Events = new CertificateAuthenticationEvents {
OnCertificateValidated = context => {
// custom validation, e.g. checking against an allowlist of thumbprints
context.Success();
return Task.CompletedTask;
}
};
});
Real-world example
A B2B payment processing API requires partner organizations to present a client certificate issued specifically for their integration, cryptographically verifying the calling party's identity beyond just an API key, appropriate for a high-security financial integration.
Common follow-ups: How does mTLS certificate validation and revocation checking work in practice?;What's the operational complexity of distributing and rotating client certificates to multiple partner organizations?
Authentication;Hosting Models: Kestrel
IIS & Reverse Proxies
What is certificate pinning, and why is it generally discouraged for typical web API scenarios despite its security benefits?
Intermediate
Certificate pinning hardcodes a client's trust to one specific certificate (or public key) rather than trusting any certificate issued by a recognized CA, defending against a compromised or rogue CA issuing a fraudulent certificate for your domain -- however, it's generally discouraged for typical scenarios because it creates a serious operational risk: if the pinned certificate needs to be rotated/renewed (planned or due to compromise) and the pinning configuration isn't updated in lockstep across all clients, those clients become completely unable to connect, a self-inflicted outage that's happened to major companies historically.
// Example of certificate pinning logic (generally NOT recommended for typical scenarios)
var handler = new HttpClientHandler {
ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => {
var expectedThumbprint = "AABBCCDD...";
return cert?.GetCertHashString() == expectedThumbprint;
}
};
Real-world example
A mobile banking app that implemented certificate pinning for its API calls experienced a complete outage for all users after a routine certificate renewal, since the pinned certificate hash in the already-deployed app version no longer matched, illustrating why pinning requires extremely careful, coordinated rotation planning.
Common follow-ups: What are safer alternatives to full certificate pinning that still improve on default CA trust, like public key pinning with backup pins?;In what specific scenarios (like a fixed-purpose IoT device) might pinning's trade-offs actually be worthwhile?
Security Headers
Antiforgery & CSRF Protection;HttpClient & Resilience (Polly)
How would you implement automated, zero-downtime certificate renewal using Let's Encrypt (ACME protocol) for a production ASP.NET Core deployment?
Advanced
Libraries like LettuceEncrypt (or infrastructure-level ACME clients like Certbot, or a managed platform's automatic HTTPS like Azure App Service) automate the entire Let's Encrypt certificate lifecycle: initial issuance, periodic renewal well before the (typically 90-day) expiration, and hot-swapping the new certificate into Kestrel's listener without requiring a process restart or any downtime -- eliminating the manual, error-prone process of tracking expiration dates and manually renewing/redeploying certificates.
// Program.cs -- using LettuceEncrypt for automatic Let's Encrypt certificate management
builder.Services.AddLettuceEncrypt(options => {
options.DomainNames = new[] { "api.example.com" };
options.EmailAddress = "admin@example.com";
});
// LettuceEncrypt handles the ACME challenge, issuance, and automatic renewal transparently,
// hot-swapping the certificate into Kestrel without a restart
Real-world example
A small SaaS company running their own Kestrel-based deployment (rather than a managed platform) integrates LettuceEncrypt, eliminating a previously manual quarterly task of renewing and redeploying their TLS certificate, with renewals now happening automatically and transparently weeks before expiration.
Common follow-ups: What is the ACME HTTP-01 challenge, and what network access does it require during the renewal process?;How does this compare to relying on a managed platform's (like Azure App Service's) built-in automatic HTTPS management?
Hosting Models: Kestrel
IIS & Reverse Proxies;Background Tasks & Hosted Services
What TLS protocol versions and cipher suites should a modern ASP.NET Core application support, and how do you configure Kestrel to enforce a minimum acceptable TLS version?
Intermediate
Modern best practice restricts supported protocols to TLS 1.2 and TLS 1.3 (disabling the older, cryptographically weaker TLS 1.0/1.1 and SSL entirely), configured via SslProtocols on Kestrel's HTTPS options -- cipher suite selection on newer .NET/OS combinations is largely managed by the underlying OS TLS stack (schannel on Windows, OpenSSL on Linux) rather than fully controllable from application code, so keeping the OS and .NET runtime patched is equally important for maintaining strong cipher suite support.
builder.WebHost.ConfigureKestrel(options => {
options.ConfigureHttpsDefaults(o => {
o.SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls13;
});
});
Real-world example
A security audit flags that an older deployment still had TLS 1.0 enabled as a legacy compatibility measure, and the team explicitly restricts Kestrel to TLS 1.2/1.3 only, immediately failing the audit's automated scan for weak protocol support and closing off known cryptographic vulnerabilities in the older protocol versions.
Common follow-ups: How would you test which TLS versions and cipher suites a deployed endpoint actually supports (like using an external SSL testing tool)?;What legacy client compatibility trade-off do you make by disabling TLS 1.0/1.1 entirely?
Security Headers
Antiforgery & CSRF Protection;Hosting Models: Kestrel
IIS & Reverse Proxies
How would you implement Server Name Indication (SNI)-based certificate selection in Kestrel, serving different TLS certificates for different hostnames on the same IP/port?
Advanced
Kestrel's ServerCertificateSelector delegate (set via ConfigureHttpsDefaults or per-listener HttpsOptions) is invoked during the TLS handshake with the requested hostname (from the SNI extension the client sends before encryption begins), letting you dynamically return the appropriate certificate for that specific hostname -- essential for multi-tenant applications hosting many custom domains on shared infrastructure, where provisioning a dedicated IP/port per domain wouldn't be practical.
builder.WebHost.ConfigureKestrel(options => {
options.ConfigureHttpsDefaults(httpsOptions => {
httpsOptions.ServerCertificateSelector = (connectionContext, hostName) => {
return _certificateStore.GetCertificateForHostname(hostName);
};
});
});
Real-world example
A multi-tenant SaaS platform serving hundreds of customer custom domains (each with their own TLS certificate) on a single shared IP address implements SNI-based certificate selection, dynamically returning the correct tenant-specific certificate at the TLS handshake stage based on the hostname the client is connecting to.
Common follow-ups: How do you handle a client that doesn't support SNI (very old browsers/clients)?;How would you efficiently cache and refresh certificates in the ServerCertificateSelector delegate to avoid expensive lookups on every handshake?
Configuration & Options Pattern;Hosting Models: Kestrel
IIS & Reverse Proxies
Why is it important to validate a server's TLS certificate when making outbound HttpClient calls to external services, and what's the risk of disabling certificate validation?
Intermediate
By default, HttpClient validates the remote server's certificate against trusted CAs, protecting against man-in-the-middle attacks where a malicious actor intercepts and impersonates the intended destination -- disabling this validation (via ServerCertificateCustomValidationCallback returning true unconditionally) is sometimes done carelessly to work around a certificate problem during development, but doing so in production removes this fundamental protection entirely, making the application vulnerable to traffic interception even over what appears to be an HTTPS connection.
// DANGEROUS -- disables certificate validation entirely, should never reach production
var handler = new HttpClientHandler {
ServerCertificateCustomValidationCallback = (msg, cert, chain, errors) => true // accepts ANY certificate
};
// SAFER -- validate against a specific known issue rather than disabling entirely
var saferHandler = new HttpClientHandler {
ServerCertificateCustomValidationCallback = (msg, cert, chain, errors) => {
return errors == SslPolicyErrors.None || IsKnownAcceptableException(cert);
}
};
Real-world example
A code review catches a developer's temporary workaround (unconditionally returning true from ServerCertificateCustomValidationCallback to bypass a local self-signed certificate issue) that had accidentally been left in and merged toward production, which would have silently disabled TLS certificate validation for all outbound calls from that service.
Common follow-ups: What's a safer, narrower workaround for a legitimate development-only self-signed certificate issue?;How would you detect if certificate validation has been inadvertently disabled somewhere in a large codebase?
HttpClient & Resilience (Polly);Security Headers
Antiforgery & CSRF Protection