简体   繁体   中英

Programmatically implement WCF with Certificate

I am quite new to WCF and trying to get my head around the security. I am still reading and learning, but I came to a point where I got a working version of WCF with Certificate authentication. I know that the code has some weaknesses; however, my initial goal was to create communication using certificate authentication. Also, I wanted to create everything programmatically (no Web.config configurations for the services or clients). The reason for this is that the client should be able to link an Assembly (Class Library) and get access to the server. Also, I am loading the certificates from the file system (again, I know this is not secure). I would like to get a little bit feedback.

The following client snippet is creating an object that I can use to connect to the server. The anonymous type T is my service interface eg IService.

Here is my client implementation:

var url = "URL TO WS";
var binding = new WSHttpBinding
{
    Security =
    {
        Mode = SecurityMode.Message,
        Message = {ClientCredentialType = MessageCredentialType.Certificate}
    }
};

var endpoint = new EndpointAddress(url);
var channelFactory = new ChannelFactory<T>(binding, endpoint);

if (channelFactory.Credentials != null)
{
    channelFactory.Credentials.ClientCertificate.Certificate =
        new X509Certificate2(@"PATH\TO\Client.pfx"); // Client Certificate PRIVATE & PUBLIC Key
    channelFactory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None; // I know this is not good, but I dont have a valid certificate from a trusted entity
}

wcfClient = channelFactory.CreateChannel();
return wcfClient;

The service is a bit more complex. I use .svc files with their code-behind. If I understand the use of .svc files correctly, then I believe this is the entry point where the .NET framework creates a ServiceHost and automatically opens it? In my implementation I do not open the ServiceHost, I only implemented a ServiceHostFactoryBase and referenced it in the .svc Markup language. Look at the Factory section - this is the part where I implement my custom Host Factory.

<%@ ServiceHost Language="C#" Debug="true"
    Service="Service.Services.LevelService" CodeBehind="LevelService.svc.cs" 
    Factory="Service.Security.ServiceHostFactory.HostFactory" %>

And my custom Host Factory looks like this:

public class HostFactory : ServiceHostFactoryBase
{
    public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
    {
        var serviceType = Type.GetType(constructorString);

        if (serviceType.GetInterfaces().Count() != 1)
            throw new NotImplementedException("The service can only have one implemented interface");

        var interfaceType = serviceType.GetInterfaces()[0];

        var myServiceHost = new ServiceHost(serviceType, baseAddresses);

        var httpBinding = new WSHttpBinding();
        httpBinding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
        httpBinding.Security.Mode = SecurityMode.Message;

        myServiceHost.Credentials.ServiceCertificate.Certificate = new X509Certificate2(@"PATH\TO\Server.pfx");
        myServiceHost.Credentials.ClientCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.Custom;
        myServiceHost.Credentials.ClientCertificate.Authentication.CustomCertificateValidator = new MyX509CertificateValidator();
        myServiceHost.Credentials.ClientCertificate.Certificate = new X509Certificate2(@"PATH\TO\Client.cer");
        myServiceHost.AddServiceEndpoint(interfaceType, httpBinding, String.Empty);

        return myServiceHost;
    }
}

The custom validator doess't do much yet, but here it is as well:

public class MyX509CertificateValidator : X509CertificateValidator
{
    public override void Validate(X509Certificate2 certificate)
    {
        // Check that there is a certificate.
        if (certificate == null)
        {
            throw new ArgumentNullException("certificate");
        }

        // Check that the certificate issuer matches the configured issuer.
        //throw new SecurityTokenValidationException("Certificate was not issued by a trusted issuer");
    }
}

If I understand correctly, the Server has ONLY the PUBLIC key of the client registered since I only reference the .cer file.

My big question is now, if I would like to get anything like this on a production server - and lets assume nobody will actually get the executables (including the certificates), would this be a possible solution to keep unwanted people out of my webservice? Basically, I don't want anybody else consuming my webservice - only if you have the proper certificate. Also, how much of an issue is the part where I set on the client:

CertificateValidationMode = X509CertificateValidationMode.None

I know there are many questions - but overall, I would like to know if I made some fundamental mistakes in this implementation.

Ok,

after going through a lot of tutorials and demo applications, I figured out that the best way to go ahead is actually using the Certificate Store on Windows. However, I still might consider a hybrid solution where the Server has the certificates in the Certificate store and the client has it embedded in a resource. If you are struggling with WCF and Certificates, have a look at those links:

IIS7 Permissions Overview - ApplicationPoolIdentity

I was able to create Transport as well as Message secured WCF web services. I would suggest to READ the linked articles because there is so much information that will make you understand certificates and their usage. Especially when dealing with self-singed certificates!

I ended up implementing wsHttpBinding using Message Security Mode + Client Certificate with ChainTrust.

Hope this will help someone else!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM