WCF showing 403 Forbidden using SSL and client certificates - c#

We are having a problem with WCF - we are getting the error below when trying to connect. There are tons of suggestions for various configurations, having tried them all we could use some help.
We are using HTTPS for transport security, using a real SSL certificate that we got from GoDaddy. It seems to be installed and working properly when we browse to web pages on the site. With no authentication, we can connect properly to our WCF service.
For authentication, we are using client certificates that we created ourselves. These client certificates were working fine before we switched to HTTPS, when we were using message security with a self-signed server certificate (which was a pain because we had to get the clients to install the server certificate).
Error
The HTTP request was forbidden with client authentication scheme 'Anonymous'.
Inner exception: The remote server returned an error: (403) Forbidden
Server configuration file
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="NewBinding0">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="WcfService1.Service1">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="NewBinding0" contract="WcfService1.IService1" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="PeerTrust" />
</clientCertificate>
<serviceCertificate findValue="....." x509FindType="FindByThumbprint" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add scheme="https" binding="wsHttpBinding" bindingConfiguration="NewBinding0" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
Client configuration file
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="NewBehavior0">
<clientCredentials>
<clientCertificate findValue="customuser1"
storeName="TrustedPeople" x509FindType="FindBySubjectName" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="NewBinding0">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://www.insertoursitename.com/WcfService1/Service1.svc"
behaviorConfiguration="NewBehavior0" binding="wsHttpBinding"
bindingConfiguration="NewBinding0" contract="ServiceReference1.IService1"
name="wsHttpBinding_IService1" />
</client>
</system.serviceModel>

My problem was very similar to yours, and i'll describe my scenario before answering the question.
Created a simple WCF service (using custom binding, but that's irrelevant).
Created a self-signed RootCA using makecert, and generated two certs tempCertServer.cer used for SSL encryption, configure IIS to require https, etc.
--> Tested this part, worked ok from the Browser from a different computer.
The second cert tempCertClient.cer was used as a client-cert to be presented to IIS, configure IIS to Require client-cert, etc. --> Tested this part from a browser (best to use IE since you can easily clear SSL state). I get a prompt to choose a client cert, but never connects, the error is exactly the same as per the question:
"The HTTP request was forbidden with client authentication scheme 'Anonymous'. Inner exception: The remote server returned an error: (403) Forbidden."
Replaced tempCertClient with a proper cert (from a known CA), there was no issue, connection was established and WCF page shown; No matter what i tried with the self-signed client cert, always getting above error.
Wasted a whole day++ trying various settings, reading blogs on registry changes, placing the cert server-side under different cert stores, changing config file settings, etc, with no resolution.
The answer was very simple, inspect the LocalComputer\Trusted Root Certification Authorities server-side, and remove any NON-ROOT CA's (i.e. those that should not be there, IssuedTo NOT EQUALS IssuedBy)
The client-cert itself did not need to be installed on the server, only a Root CA that can validate it has to be installed in LocalComputer\Trusted Root Certification Authorities server-side.

Related

Add WCF Service Reference to Visual Studio 2022 Project with Client Certificate

I am attempting to add a WCF Web Service reference to a C# project where the WSDL is secured behind a client certificate. I have successfully added the certificate to SOAPUI and made calls just fine, but when I attempt to add the reference in Visual Studio, I dont get prompted to select the certificate.
How do I add a WCF Service endpoint which requires a client certificate in Visual Studio 2022 Community?
Specify the client certificate using endpoint behavior like below:
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="endpointCredentialsBehavior">
<clientCredentials>
<clientCertificate findValue="Cohowinery.com"
storeLocation="LocalMachine"
x509FindType="FindBySubjectName" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_ICalculator" >
<security mode="Message">
<message clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://machineName/Calculator"
behaviorConfiguration="endpointCredentialsBehavior"
binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_ICalculator"
contract="ICalculator"
name="WSHttpBinding_ICalculator">
</endpoint>
</client>
For more information, check out Message Security with a Certificate Client or Transport Security with Certificate Authentication.

WCF Certificate Based Authentication Issue. Service is Getting authenticated with an invalid Certificate

I'm a beginner with WCF services. Trying to implement a Certificated based authentication on a WCF service and facing an issue. The service expects a specific Certificate from the calling client. The server throws an authentication error if the client is not passing any certificate. But at the same time, the service call is passing authentication with any certificates provided by the client(The service suppose to authenticate if the client provides a specific certificate).
Following is the code snippet of server config :
Service Config :
<bindings>
<wsHttpBinding>
<binding name="MyWsHttpBinding" maxReceivedMessageSize="2147483647" receiveTimeout="00:30:00">
<readerQuotas maxStringContentLength="2147483647" maxBytesPerRead="2147483647" maxDepth="2147483647" maxArrayLength="2147483647"/>
<security mode="Transport">
<transport clientCredentialType="None" proxyCredentialType="None"/>
<message clientCredentialType="Certificate" algorithmSuite="Default"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<serviceBehaviors>
<behavior name="MyServiceBehavior">
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="ChainTrust" />
</clientCertificate>
<serviceCertificate findValue="e616ebcd940951794736624acc6484802018c8d4" storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint" />
</serviceCredentials>
<serviceMetadata httpsGetEnabled="true" httpGetEnabled="true"/>
<CustomBehaviorExtensionElement/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="MyEndpointBehavior">
<MySchemaValidator validateRequest="True" validateReply="False">
<schemas>
<add location="App_Data\model-service.xsd"/>
</schemas>
</MySchemaValidator>
</behavior>
</endpointBehaviors>
<services>
<service name="MyService" behaviorConfiguration="MyServiceBehavior">
<endpoint binding="wsHttpBinding" bindingConfiguration="MyWsHttpBinding" contract="MyExchangeService" behaviorConfiguration="MyEndpointBehavior" bindingNamespace="http://www.mycompany.com/exchange/"/>
<endpoint contract="IMetadataExchange" binding="mexHttpsBinding" address="mex" name="mex"/>
</service>
</services>
The cause of the problem is the security mode you use is transport, so only the following code works:
<transport clientCredentialType="None" proxyCredentialType="None"/>
The following message settings have no effect:
<message clientCredentialType="Certificate" algorithmSuite="Default"/>
Change the value in transport to certificate, you can also download the wcf demo on the official website, there are examples of related certificate verification, and there are tutorials corresponding to the demo.
I see that the certificate validation mode used in your code is ChainTrust.
<clientCertificate>
<authentication certificateValidationMode="ChainTrust" />
</clientCertificate>
As mentioned in Microsoft Docs, using ChainTrust means -
The certificate is valid if the chain builds to a certification authority in the trusted root store
Meaning, the client need not send certificate with the exact same thumbprint as mentioned in your service web.config. Infact, any certificate whose Root / Intermediate Certification Authority is present in your VM's Trusted Root Store will pass validation.
To make sure that the client is able to use only a specific certificate to authenticate to your service, change ChainTrust to PeerTrust and add the certificate to the trusted people store on your VM's Certificate Store (certmgr).
<authentication certificateValidationMode="PeerTrust" />
References:
MS Docs - Working with certificates in WCF
Authentication element in web.config
More info on Certificate Chain of Trust

WCF w/ mutual authentication

I'm trying to help troubleshoot a third-party self-hosted web service written in WCF that requires mutual authentication. The issue is that web service is returning a 401 Unauthorized. I've read several articles about how to write the client and server pieces in WCF to use mutual authentication, but I still have the following questions:
Once the client sends the client certificate, how does the WCF service determine whether or not to accept it as being an authenticated endpoint with access to the given resource. Does the certificate only need to be trusted by the service being able to find the certificate's root CA in the certificate store as a trusted root CA, or is there some mechanism that maps the certificate to a list of entities that have been identified as allowed to access the resource?
Normally when I've seen mutual authentication used, in Wireshark I see the server respond to a Client Hello and Certificate Request with a Server Hello, Certificate, and Certificate Request. However, in the case I am troubleshooting, I do not see the server send a Certificate Request. I believe the client is sending its certificate in encrypted data, but I'm not able to decrypt the data to see it. Is there a way to force the WCF service to send a Certificate Request with the Server Hello?
The configuration file has the following:
<bindings>
<webHttpBinding>
<binding name="webHttpTransportSecurity">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</webHttpBinding>
</bindings>
I believe that's enough to indicate the client should authenticate with a certificate, but now how the service decides if that certificate is one that's allowed?
Your binding definition looks correct. The certificate is defined in the endpointBehaviors. It is a little hard to follow, because it is split-up in separate XML groups.
Here is an example of what is working for my projects:
<client>
<endpoint address="(address to our)WebService.svc"
behaviorConfiguration="behaviorConfig"
binding="webHttpTransportSecurity"
bindingConfiguration="bindingConfig"
contract="((your contract name))"
name="mainEndPoint">
<identity>
<certificateReference findValue="CN=((cert name like blah.blah.blah-blah.blah)), OU=((lookup)), O=((lookup))"
storeLocation="LocalMachine"
storeName="TrustedPeople"
x509FindType="FindBySubjectDistinguishedName" />
</identity>
</endpoint>
</client>
<bindings>
<!-- you already have a good looking binding (above) -->
</bindings>
<behaviors>
<serviceBehaviors ...etc />
<endpointBehaviors>
<behavior name="behaviorConfig">
<clientCredentials>
<clientCertificate findValue="CN=((short name)), OU=((lookup)), O=((lookup))"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectDistinguishedName" />
<serviceCertificate>
<defaultCertificate findValue="CN=((same content from certificateReference above)), OU=((lookup)), O=((lookup))"
storeLocation="LocalMachine"
storeName="TrustedPeople"
x509FindType="FindBySubjectDistinguishedName" />
<authentication certificateValidationMode="PeerTrust"
revocationMode="NoCheck"
trustedStoreLocation="LocalMachine" />
</serviceCertificate>
</clientCredentials>
<callbackTimeouts />
</behavior>
</endpointBehaviors>
</behaviors>

Add additional SSL behavior for WCF endpoint within Azure Web Role

Our azure web application already uses https port 443 with our site certificate, we have a WCF service within this webrole that has an https endpoint using our cert to authenticate (1-way ssl), this same service needs an additional https endpoint supporting 2-way auth using our cert and the third party's cert. We have uploaded the cert, updated the service definition file, and added an endpoint that we are hoping will work, but in testing we are getting the error: The SSL settings for the service 'SslRequireCert' does not match those of the IIS 'None'.
so the endpoint that does work is: https://environemnt.application.com/Services/Service.svc
the endpoint that generates the error: https://environment.application.com/Services/Service.svc/twa
The key requirement is that it is https, port 443, at the above new endpoint, without altering the SSL behavior of the rest of the role, I have seen entries to change the IIS configuration or use the role editor to add an Https Input endpoint, but as we already have an Https Input endpoint on port 443 using our site cert I don't want to alter/affect the whole role.
If it is helpful the service is a WCF Service which consumes an Mtom encoded soap 1.2 message
here are the new values that we have entered, what else do I need?
<behaviors>
<serviceBehaviors>
<behavior name="SSLServiceBehavior">
<serviceMetadata httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<dataContractSerializer maxItemsInObjectGraph="2147483647" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="OneWayAuthEndpointBehavior">
</behavior>
<behavior name="TwoWayAuthEndpointBehavior">
<endpointDiscovery enabled="true"></endpointDiscovery>
<clientCredentials>
<clientCertificate findValue="thumprint..." storeLocation="LocalMachine" storeName="CertificateAuthority" x509FindType="FindByThumbprint" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="SSLServiceBehavior" name="Service">
<endpoint address="" behaviorConfiguration="OneWayAuthEndpointBehavior"binding="wsHttpBinding" bindingConfiguration="HttpsMtomOneWay" contract="ITestService" />
<endpoint address="twa" behaviorConfiguration="TwoWayAuthEndpointBehavior" binding="wsHttpBinding" bindingConfiguration="HttpsMtomTwoWay" contract="ITestService"/>
</services>
<bindings>
<wsHttpBinding>
<binding name="HttpsMtomOneWay" messageEncoding="Mtom">
<security mode="Transport">
<transport clientCredentialType="None" />
</security>
</binding>
<binding name="HttpsMtomTwoWay" messageEncoding="Mtom">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
thank you much
Fixed through these steps:
Added serviceCredentials.serviceCertificate (cert details for our cert) to the service behavior
Eliminated Endpoint behavior definitions
Changed the HttpsMtomTwoWay binding to securityMode=Message
Now the message handlers handle the authentication exchange and external cert validation, then pass on to the transport endpoint, and we did not need to mess with the site wide SSL or endpoint settings. Tested and verified with numerous 3rd parties.

WCF in IIS, http basic authentication - Windows User "security" implications

I created a WCF Service, using http Basic Authentication and SSL. (Temporary certificate in IIS atm)
Here is the relevant configuration.
<services>
<service name="MyNamespace.MyService">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicHttps"
name="MyEndPoint" contract="MyNamespace.IMyService" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="">
<!-- These will be false when deployed -->
<serviceMetadata httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
<!-- This doesn't do anything in IIS -->
<behavior name="CustomUsernameValidatorBehavior">
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="MyNamespace.CustomUserNameValidator" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="basicHttps">
<security mode="Transport">
<transport clientCredentialType="Basic" />
</security>
</binding>
</basicHttpBinding>
</bindings>
Due to the fact I am hosting in IIS, I can't use my customUsernameValidator, and IIS Basic authentication tries the username and password against Windows.
I created a new user, disabled logon locally, and put it in a new group (without rights). The only purpose of the user is to ensure they are allowed to access the service, nothing else. The service will be online, not internal e.g. in an Intranet etc.
My question boils down to this, is there security risks/implications due to the fact I am using a real windows user? What can be done to secure this service/IIS if so?
Should something be done to prevent 'phishing' of information, could they for example try different usernames and passwords to find credentials?
Btw this is a working binding (minus some other endpoints etc.) for WCF using Http Basic Authentication in IIS and SSL. It requires IIS has Basic Authentication installed, as well as a Windows User to authenticate against. I would prefer not to authenticate against a Windows user.
IIS 5.0 and below version has IP address disclosure vulnerability if Basic Authentication (with no realm defined) is used.
Please have a look at this site:
http://www.juniper.net/security/auto/vulnerabilities/vuln1499.html

Categories

Resources