537mfb
537mfb

Reputation: 1482

WCF Service over HTTPS without IIS, with SSL Certificate from CERT and KEY strings or files

I've done work with WCF before - but since it was for in-house use only, not accessable from the internet at all, i just used net.tcp and not cared much about security.

However, i am now in pre-production for a project that will be made availlable over the internet to customers, so security must be planed for.

I've been doing some research on the matter, and from what i gathered (correct me if I am wrong here), HTTPS is my best bet, as HTTP isn't secured at all (by default) and net.tcp could find problems with some firewalls.

Howerer, I don't want to force customers to have to install IIS in their servers if they don't want to, so the plan is to use a self hosted Windows Service. However, i can't seem to find any information on how to setup the server to use HTTPS without na IIS.

  1. I found information about using makecert and httpcfg set ssl to add a new certificate to the store and then set it to a port - that's ok for testing but i'm not seeing this feaseable in the customer's server - not to mention this means i'll be using aself signed certificate - again ok for testing, not so much in production

  2. I also found information (ServiceCredentials MSDN page) about using something like

    sh.Credentials.ServiceCertificate.SetCertificate(
        StoreLocation.LocalMachine, StoreName.My,
        X509FindType.FindByThumbprint, 
        "af1f50b20cd413ed9cd00c315bbb6dc1c08da5e6");
    

to set a certificate that is already in the server's certificate store - that would almost be ok - it still require the customer to know how to manage certificates in the store, not perfect but ok. However i couldn't get it to work - i don't get any error starting the servisse, but if i try to go to the service address in a browser i get na error regarding TLS beeing out of date - Q1: Any idea what could be the problem here?

Q2: Is it possible to have a configuration somewhere where the customer could input the has or at least location for the cert and key files one gets when buying a certificate and use that to secure the service?

Upvotes: 0

Views: 3062

Answers (1)

Abraham Qian
Abraham Qian

Reputation: 7522

Q1: As mentioned in the errors, there may be a problem in your certificate. be sure that the certificate is valid(self signed certificate can not expire).
Q2: As far as I know, we could save the certificate as a file(pfx, cert) or install the certificate in the certificate store(certlm.msc, certmgr.msc) in order to manage.
Do you want to host the WCF service over https in windows service project? I have made a demo, wish it is useful to you.
Service1.cs

public partial class Service1 : ServiceBase
        {
            public Service1()
            {
                InitializeComponent();
            }
            Uri uri = new Uri("https://localhost:1017");
            ServiceHost sh = null;
            protected override void OnStart(string[] args)
            {
                BasicHttpBinding binding = new BasicHttpBinding();
                binding.Security.Mode = BasicHttpSecurityMode.Transport;
                binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
                try
                {
                    ServiceHost sh = new ServiceHost(typeof(MyService), uri);
                    sh.AddServiceEndpoint(typeof(IService), binding, "");
                    ServiceMetadataBehavior smb;
                    smb = sh.Description.Behaviors.Find<ServiceMetadataBehavior>();
                    if (smb == null)
                    {
                        smb = new ServiceMetadataBehavior()
                        {
                            HttpsGetEnabled=true,
                        };
                        sh.Description.Behaviors.Add(smb);
                    }
                    Binding mexbinding = MetadataExchangeBindings.CreateMexHttpsBinding();
                    sh.AddServiceEndpoint(typeof(IMetadataExchange), mexbinding, "mex");
                    sh.Open();
                    WriteLog($"Service is ready at {DateTime.Now.ToString("hh-mm-ss")}");
                }
                catch (Exception e)
                {
                    WriteLog(e.ToString());
                    throw;
                }
            }

            protected override void OnStop()
            {
                if (sh!=null&&sh.State==CommunicationState.Opened)
                {
                    sh.Close();
                    WriteLog($"Service is closed at {DateTime.Now.ToString("hh-mm-ss")}");
                }
            }

            public static void WriteLog(string text)
            {
                using (StreamWriter sw = File.AppendText(@"C:\Mylog.txt"))
                {
                    sw.WriteLine(text);
                    sw.Flush();
                }
            }
        }
        [ServiceContract(Namespace = "mydomain")]
        public interface IService
        {
            [OperationContract]
            string SayHello();
        }
        public class MyService : IService
        {
            public string SayHello()
            {
                Service1.WriteLog(string.Format("Wow, I have been called at {0}", DateTime.Now.ToString("hh-mm-ss")));
                return "Hello stranger";
            }
    }

ProjectInstaller.cs
enter image description here
enter image description here
Install the windows service(administrator privilege CMD)
enter image description here
Bind the certificate to the application port.
enter image description here
https://learn.microsoft.com/en-us/windows/desktop/http/add-sslcert
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-configure-a-port-with-an-ssl-certificate
Certhash parameter specifies the thumbprint of the certificate. The appid parameter is a GUID that can be used to identify the owning application(open the project.csproj file)

<ProjectGuid>{56FDE5B9-3821-49DB-82D3-9DCE376D950A}</ProjectGuid>

Start the windows service.
enter image description here
Test(Server Ip is 10.157.13.70):
enter image description here
Client invocation(there is a step that validates the server certificate by default)

static void Main(string[] args)
    {
        ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
        ServiceReference1.ServiceClient client = new ServiceReference1.ServiceClient();
        try
        {
            var result = client.SayHello();
            Console.WriteLine(result);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

Result
enter image description here
Feel free to let me know if there is anything I can help with.

Upvotes: 1

Related Questions