Click here to Skip to main content
15,885,985 members
Articles / Web Development / ASP.NET

How to Host an ASP.NET Web Application on a Local Area Network

Rate me:
Please Sign up or sign in to vote.
5.00/5 (9 votes)
28 Apr 2021CPOL6 min read 17.7K   254   32  
How to allow private network (LAN) clients to connect to the https port of a locally hosted ASP.NET web application
Configuring a local area network so that clients can access a web application on the network can be a frustrating experience. Most of the problems arise when trying to implement the Transport Layer Security protocol. It’s hoped that the structured approach shown here will help to simplify the procedure.

Introduction

Allowing private network (LAN) clients to connect to a local Windows ASP.NET web application is not quite as easy as it seems. Simply pointing a browser at the server's ipaddress and port number doesn’t work

The Problem

By default, the app will run using the address http://localhost:5000 or https://localhost:5001. Localhost is an internal networking address, designed to connect to clients running on the same machine as the web app and it effectively discourages connections from external sources. It may be possible to connect by using http and substituting localhost for the network address of the server, but the client’s browser’s address bar with show the dreaded open lock icon and issue dire warnings about what will be visited upon you should you dare to proceed. An alternative approach is to use Https. But this type of request will rarely get further than the initial ‘hello’ hand shake. As soon as the client sees the server’s transport layer security certificate identifying the server as localhost, it will smell a rat and refuse to connect.

A Simple Solution

It’s just a matter of configuring the ASP.NET web app so that it shows a valid TLS certificate to the client during the initial ‘hello’ handshake and to enable the client to validate that certificate. You’ll need to set yourself up as your own network’s Certificate Authority (CA) in order to produce a certificate that clients will accept, but that’s no big deal. The excellent NuGet certificate management package, Concerto, makes that task easy.

Setting Up a Network Certificate Authority

Setting up a CA involves the use of public/private key asymmetric cryptography. The key point to understand about the key pairs is that data encrypted by the private key can only be decrypted by the corresponding public key and vice versa. A network certificate authority issues certificates that validate the identity of servers that run on the network. Clients need to see and validate two certificates before they will connect to a server. The first certificate is the server’s certificate. That certificate references the trusted Certificate Authority that has validated the certificate, by signing it with the CA’s private key. The client looks for the CA’s root certificate in the client’s store of trusted CAs. If it finds one, it extracts the CAs public key from the certificate and uses it to validate the server’s signed certificate. Finally, the client extracts the server’s public key from the server’s certificate and uses the key to encrypt a data packet that’s sent to the server. That packet and others that follow it enable client and server to exchange messages efficiently by using a session key to encrypt the conversation between the two machines. Three certificates need to be created.

1. The Certificate Authority’s Certificate

Create a CA authority certificate containing public and private keys. If needed, the certificate can be saved in a password protected pfx file. 

C#
CertificateChainWithPrivateKey caCert = CertificateCreator.CreateCACertificate(Constants.CAname);
CertificateFileStore.SaveCertificate(caCert, cAcertPath, false, Constants.Password);

2. The Certificate Authority’s Root Certificate

Save the CA's root certificate in a 'cer' file. It contains only the CA's public key. This certificate needs to be added to each client's trusted root certificate store.

C#
CertificateFileStore.SaveCertificate(caCert, cArootPath);

3. The Server’s Certificate

Use the CA's private key to issue a signed certificate to the server (host)

C#
var hostCert = CertificateCreator.CreateCertificate(new[] { Constants.HostIpAddress },caCert); 
CertificateFileStore.SaveCertificate(hostCert, hostCertPath, false, Constants.Password);

Storing Certificates

The best approach is to store the certificates in one of Windows certificate stores and let Windows manage the certificates at that location. There’s an interesting blog post detailing the problems that can arise from the incorrect management of certificates. To manage the current user certificate store, press the Windows key, then search for and select 'manage user certificates'. The folders inside the current user’s certificate store will be displayed. On a client’s machine, store the CA’s root certificate in the Trusted Root Certificate Authorities Certificates sub folder. Right click on the folder and select 'All Tasks/import'. Browse to the location of the CAroot.cer file, select it and follow the prompts. Do the same sort of thing on the server but select the Personal/Certificates folder as the location and import from both HostCert.pfx and CAcert.pfx. You will need to change the extension filter in File Explorer so that it references pfx. Rather than cer or you will not see them in the list. Pfx and cer are format references that prescribe the structure of the saved certificate

Configuring the Web Application

ASP.NET uses Kestrel as its server. Kestrel is a joy to configure, just add the following to the web app’s appsettings.json file – remember to change the Urls and Subject name to reference your own server’s address.

C#
"Kestrel": {
  "Endpoints": {
    "Http": { //reference the sever's network ipaddress here
      "Url": "http://192.168.1.14:5000"
    },
    "HttpsInlineCertStore": {
      "Url": "https://192.168.1.14:5001",
      "Certificate": {
        "Subject": "192.168.1.14",
        "Store": "My",
        "Location": "CurrentUser", //default
        "AllowInvalid": false //default
      }
    }
  }
}

Launching the Server

It’s best to launch the web app using the command prompt. To do this, simply select the project name in Visual Studio’s launch box. Kestrel doesn’t need to use IIS so I’d avoid choosing that option. All that’s needed now is to point a client’s browser at the servers ipaddress and the Https port that the server listens on. Something like https://192.168.1.10:5001.

The Example App

The example app produces the required three TLS certificates. Configuration is by way of a constants class, it needs to be changed to suit your requirements. You will also need to know the server’s network Ipaddress. The easy way to do this is to enter 'ipconfig' at a command prompt and search for the IPv4 Address in the output. Another point is that the method that produces the .cer file also outputs the CA’s private key as a .key file. Setting the isDeletePrivateKey bool in the Constants class will result in the key being deleted. It has already been stored in the CA’s certificate so it is not required. The project is very simple. Here’s the main source code:

C#
 static public void CreatNetworkCertificates()
 {
     var cAcertPath = AddFileNameToPath(Constants.CAcertFile);
     var cArootPath = AddFileNameToPath(Constants.CArootFile);
     var hostCertPath = AddFileNameToPath(Constants.HostCertFile);
     var keyFilePath = Path.ChangeExtension(cArootPath, ".key");
     List<string> filepaths = new() { cAcertPath, cArootPath, hostCertPath, keyFilePath };
     var existingFiles = filepaths.Where(p => File.Exists(p));
     if (existingFiles.Any())
     {
      Console.WriteLine("The following files already exist. Please remove them and try again");
      Console.WriteLine(string.Join(", ", existingFiles.ToArray()));
      return;
     }
     Console.WriteLine("Creating CA certificate...");
     var caCert = CertificateCreator.CreateCACertificate(Constants.CAname);

     Console.WriteLine($"Saved CA certificate in {cAcertPath}");
     CertificateFileStore.SaveCertificate(caCert, cAcertPath, false, Constants.Password);

     CertificateFileStore.SaveCertificate(caCert, cArootPath);
     Console.WriteLine($"Saved CA root certificate in {cArootPath}");

     //The CA's private key is also exported in a separate .key file. So need to delete 
     //that file as the CA's private key has already been saved in a pfx file
     if (Constants.IsDeletePrivateKey)
     {
      File.Delete(keyFilePath);
     }

     var hostCert = CertificateCreator.CreateCertificate(new[] { Constants.HostIpAddress },
                                                                 caCert);
     CertificateFileStore.SaveCertificate(hostCert, hostCertPath, false, Constants.Password);
     Console.WriteLine($"Saved host's certificate in {hostCertPath}");
 }
 static string AddFileNameToPath(string fileName) => Path.Combine(Constants.FilePath, 
                                                                     fileName);
}

Debugging

If your browser is raising error messages, use the browser's developer tools/security section to get a better description of the problem than can be obtained by simply clicking on the open lock icon. Don’t be surprised if the error messages are not very helpful, they are intentionally vague for security reasons. It’s not good policy to tell hackers exactly what they need to fix.

The Wireshark application is excellent for examining network data packets. It’s a good idea to use a filter to sieve out only the conversations between the server and clients. The illustration below shows part of a Wireshark trace. There’s a simple filter in place (tcp.port==5001) that restricts selections to the transactions on the web app’s listening port. It shows details of the initial handshake and application data exchange. The last data packet shown confirms that the server is about to send encrypted data using the agreed session key.

Image 1

Lessons Learned

Always clear the SSL certificate cache after replacing a certificate or your browser may continue to use the old one. To do this, press the Windows key, then search for and select 'internet options' in the search panel. Next, select the content tab and click the 'Clear SSl state' button. I thought that certificate caching was the browser’s responsibility but, apparently, Windows has now taken on that task.

Conclusion

Staging a web app on a local network can be a useful step in development as it enables performance to be assessed on machines running in a different environment than the one that the app was built on. The use of Kestrel means that configuration is simple and there’s no need to mess with IIS, an activity that, in my experience, nearly always ends in tears.

Acknowledgements

I'd like to thank Sebastian Solnica , the author of Concerto, for his many interesting posts and for adapting Concerto so that it can handle Window's file extensions.

History

  • 28th April, 2021: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Student
Wales Wales
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --