.NET
SSL certificate
web services
error handling
debugging

Bypass invalid SSL certificate errors when calling web services in .Net

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

When calling HTTPS web services in .NET, the runtime validates the server's SSL/TLS certificate. If the certificate is self-signed, expired, or has a domain mismatch, the call fails with an AuthenticationException or WebException. During development and testing, you may need to bypass this validation. In .NET Framework, you set ServicePointManager.ServerCertificateValidationCallback. In .NET Core/.NET 5+, you configure HttpClientHandler.ServerCertificateCustomValidationCallback. Both approaches should only be used in development — disabling certificate validation in production exposes your application to man-in-the-middle attacks.

.NET Core / .NET 5+ (HttpClient)

csharp
1using System.Net.Http;
2
3// Create handler that bypasses SSL validation
4var handler = new HttpClientHandler
5{
6    ServerCertificateCustomValidationCallback =
7        HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
8};
9
10var client = new HttpClient(handler);
11var response = await client.GetAsync("https://self-signed.example.com/api/data");
12var content = await response.Content.ReadAsStringAsync();

DangerousAcceptAnyServerCertificateValidator is a built-in callback that accepts any certificate. The name intentionally signals that this is unsafe for production.

Custom Validation Callback

csharp
1using System.Net.Http;
2using System.Net.Security;
3using System.Security.Cryptography.X509Certificates;
4
5var handler = new HttpClientHandler
6{
7    ServerCertificateCustomValidationCallback = (message, cert, chain, errors) =>
8    {
9        // Accept if no errors
10        if (errors == SslPolicyErrors.None)
11            return true;
12
13        // Accept a specific self-signed certificate by thumbprint
14        if (cert?.Thumbprint == "A1B2C3D4E5F6...")
15            return true;
16
17        // Log and reject everything else
18        Console.WriteLine($"SSL error: {errors}, cert: {cert?.Subject}");
19        return false;
20    }
21};
22
23var client = new HttpClient(handler);

A custom callback lets you accept specific certificates (by thumbprint or subject) while rejecting others. This is safer than accepting all certificates.

.NET Framework (ServicePointManager)

csharp
1using System.Net;
2using System.Net.Security;
3using System.Security.Cryptography.X509Certificates;
4
5// Global setting — affects ALL requests in the application
6ServicePointManager.ServerCertificateValidationCallback =
7    (sender, certificate, chain, sslPolicyErrors) => true;
8
9// Make the request
10var client = new WebClient();
11string result = client.DownloadString("https://self-signed.example.com/api");
12
13// More targeted: only bypass for specific hosts
14ServicePointManager.ServerCertificateValidationCallback =
15    (sender, certificate, chain, errors) =>
16    {
17        if (errors == SslPolicyErrors.None)
18            return true;
19
20        // Only bypass for dev server
21        if (sender is HttpWebRequest request &&
22            request.RequestUri.Host == "dev.internal.example.com")
23            return true;
24
25        return false;
26    };

ServicePointManager.ServerCertificateValidationCallback is a global static property — it affects every HTTPS request in the process. This is the .NET Framework approach; .NET Core should use HttpClientHandler instead.

WCF Client

csharp
1using System.ServiceModel;
2using System.Net;
3using System.Net.Security;
4
5// For WCF clients, set the global callback before creating the client
6ServicePointManager.ServerCertificateValidationCallback =
7    (sender, cert, chain, errors) => true;
8
9var binding = new BasicHttpsBinding();
10var endpoint = new EndpointAddress("https://self-signed.example.com/Service.svc");
11var client = new MyServiceClient(binding, endpoint);
12
13var result = await client.GetDataAsync(42);

Environment-Based Configuration

csharp
1using Microsoft.Extensions.DependencyInjection;
2using Microsoft.Extensions.Hosting;
3
4// In Program.cs or Startup.cs
5builder.Services.AddHttpClient("InternalApi", client =>
6{
7    client.BaseAddress = new Uri("https://internal-service.local/");
8})
9.ConfigurePrimaryHttpMessageHandler(() =>
10{
11    var handler = new HttpClientHandler();
12
13    if (builder.Environment.IsDevelopment())
14    {
15        // Only bypass in development
16        handler.ServerCertificateCustomValidationCallback =
17            HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
18    }
19
20    return handler;
21});
22
23// Usage via IHttpClientFactory
24public class MyService
25{
26    private readonly HttpClient _client;
27
28    public MyService(IHttpClientFactory factory)
29    {
30        _client = factory.CreateClient("InternalApi");
31    }
32
33    public async Task<string> GetDataAsync()
34    {
35        var response = await _client.GetAsync("/api/data");
36        return await response.Content.ReadAsStringAsync();
37    }
38}

Using IHttpClientFactory with environment checks ensures SSL bypass only applies in development and only to specific named clients.

Adding a Self-Signed Certificate as Trusted

csharp
1// Instead of bypassing validation, trust the specific certificate
2
3// Linux/Docker: add cert to trusted store
4// cp my-cert.crt /usr/local/share/ca-certificates/
5// update-ca-certificates
6
7// Windows: use certmgr or PowerShell
8// Import-Certificate -FilePath .\my-cert.crt -CertStoreLocation Cert:\LocalMachine\Root
9
10// Programmatically in .NET
11var handler = new HttpClientHandler();
12handler.ClientCertificates.Add(
13    new X509Certificate2("client-cert.pfx", "password"));

Trusting the certificate at the OS level or certificate store is safer than bypassing validation entirely.

Common Pitfalls

  • Using ServicePointManager in .NET Core: ServicePointManager.ServerCertificateValidationCallback has no effect in .NET Core/.NET 5+. It only works in .NET Framework. Use HttpClientHandler.ServerCertificateCustomValidationCallback instead.
  • Leaving bypass enabled in production: Disabling certificate validation in production allows man-in-the-middle attacks. Use environment checks (IsDevelopment()) or compiler directives (#if DEBUG) to ensure the bypass only applies in development.
  • Global callback affecting all requests: ServicePointManager.ServerCertificateValidationCallback applies to every HTTPS request in the process, including third-party libraries and internal .NET calls. Use HttpClientHandler per-client instead of the global callback.
  • Not checking the specific certificate: Accepting all certificates (return true) is the least secure approach. If possible, validate the certificate thumbprint or subject to accept only the specific self-signed certificate you expect.
  • Ignoring the real fix: The best solution is usually to install a proper certificate. Use Let's Encrypt for free trusted certificates, or add your self-signed CA to the machine's trusted root store. Bypassing validation should be a temporary development measure, not a permanent solution.

Summary

  • .NET Core/.NET 5+: use HttpClientHandler.ServerCertificateCustomValidationCallback per client
  • .NET Framework: use ServicePointManager.ServerCertificateValidationCallback (global, affects all requests)
  • Gate SSL bypass with IsDevelopment() or #if DEBUG to prevent production exposure
  • Prefer trusting the specific certificate (by thumbprint or CA) over accepting all certificates
  • The best long-term fix is a proper certificate from a trusted CA or adding your CA to the trust store

Course illustration
Course illustration

All Rights Reserved.