Thursday, December 29, 2016

Implementation of WCF transport security using self-signed certificates


For implementation of WCF message security using certificates, Pl refer this post

--------------------------------------------------------------------------------------------------------




Implementation of WCF transport security using self-signed certificates

Transport layer security means using HTTPS protocol (SSL). This will make sure that the HTTP packets travel encrypted through the network. With the below configuration, you will get confidentiality (because of encryption) but YOU ARE NOT AUTHENTICATING the client. Any client can successfully call https://subhasissecureservice.com/Service1.svc as long as the client has the RootCA under its trusted roots folder. (which is generally the case. In an internet-facing scenario, the SSLs are procured from – say – Verisign. All clients PCs have Verisign in their trusted roots folder.)

Note – Transport security are for POINT-TO-POINT, while Message security are for END-TO-END. (Think about it).

Creation of SSL certificate for subhasissecureservice.com (exactly as any other cert)

makecert -n "CN=SubhasisSecureService.com" -ic "SubhasisCA.cer" -iv "SubhasisCAPrivateKey.pvk" -a sha1 -sky exchange -pe -sv "SubhasisSecureServicePrivateKey.pvk" "SubhasisSecureService_SSL.cer"
---private key password of the above is secureservicepvtkeypwd

pvk2pfx -pvk "SubhasisSecureServicePrivateKey.pvk" -spc "SubhasisSecureService_SSL.cer" -pfx "SubhasisSecureService_SSL.pfx" -pi secureservicepvtkeypwd

1.      Install the pfx in the server mmc.
2.      Make sure Root CA is in the server mmc (if not procured/purchased).
3.      Update host file with <IP> tab SubhasisSecureService.com (if DNS server is not used)
4.      Configure IIS to use site/webservice with SSL (edit bindings).
5.      Make sure Root CA is in the client mmc (if not procured/purchased).
6.      Update host file with <IP> tab SubhasisSecureService.com in the client as well. (if DNS server is not used)

Server config file (Note basicHttpBinding is used with SSL certificates)
Key sections with yellow highlight
<system.serviceModel>
    <client />
    <services>
      <service name="CertSecurityDemoService.Service1">
        <endpoint address="" binding="basicHttpBinding" bindingConfiguration="secureBasicHttpBinding" contract="CertSecurityDemoService.IService1" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>         
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <protocolMapping>
        <add binding="basicHttpsBinding" scheme="https" />
    </protocolMapping>
    <bindings>
      <basicHttpBinding>
        <binding name="secureBasicHttpBinding" sendTimeout="00:10:00" receiveTimeout="00:10:00" openTimeout="00:10:00" closeTimeout="00:10:00">
          <security mode="Transport">
            <transport clientCredentialType="None"/>
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
Client config file (Simple)
<system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_IService1">
          <security mode="Transport" />
        </binding>
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint address="https://subhasissecureservice.com/Service1.svc"
          binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService1"
          contract="ServiceReference1.IService1" name="BasicHttpBinding_IService1" />
    </client>
  </system.serviceModel>


Note – In the above config, we have clientCredentialType as “None”, which means we don’t expect to authenticate. Any client can consume the webservice.
The purpose here is to prevent “man-in-the-middle” attack. (i.e. Tampering of message)

--------------------------------------------------------------------------------------------------------

If you want to add additional security like custom username/pwd, certificates etc to validate the client (prevent anonymous access), along with transport layer security (HTTPS), You can do that by slightly modifying the above code –
1)      At the service level, change security mode to “TransportWithMessageCredential” from “Transport” (Note – TransportWithMessageCredential has high overhead) and add <message clientCredentialType="UserName"/>
2)      Add a servicebehavior to custom validate the username/password.
3)      Client config has minimal change. Only securitymode is changed to TransportWithMessageCredential.
4)      Client code should pass the username and password as shown below –
          ServiceReference1.Service1Client cl = new ServiceReference1.Service1Client();
            cl.ClientCredentials.UserName.UserName = "subhasisrout";
            cl.ClientCredentials.UserName.Password = "abcxyz!$@#";
    Console.WriteLine(cl.GetData(5));



Server config

<system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="usernamevalidatebehavior">
          <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
          <serviceCredentials>
            <userNameAuthentication customUserNamePasswordValidatorType="CertSecurityDemoService.CustomUserNameValidator, CertSecurityDemoService" userNamePasswordValidationMode="Custom"/>
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <client/>
    <services>
      <service name="CertSecurityDemoService.Service1" behaviorConfiguration="usernamevalidatebehavior">
        <endpoint address="" binding="basicHttpBinding" bindingConfiguration="secureBasicHttpBinding" contract="CertSecurityDemoService.IService1" />
      </service>
    </services>
   
    <protocolMapping>
        <add binding="basicHttpsBinding" scheme="https" />
    </protocolMapping>
    <bindings>
      <basicHttpBinding>
        <binding name="secureBasicHttpBinding" sendTimeout="00:10:00" receiveTimeout="00:10:00" openTimeout="00:10:00" closeTimeout="00:10:00">
          <security mode="TransportWithMessageCredential">
            <message clientCredentialType="UserName"/>
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>


--------------------------------------------------------------------------------------------------------



public class CustomUserNameValidator : System.IdentityModel.Selectors.UserNamePasswordValidator
    {
        public override void Validate(string userName, string password)
        {
            if (userName == null || password == null)
            {
                throw new ArgumentNullException();
            }

            if (!(userName == "subhasisrout" && password == "abcxyz!$@#"))
            {
                throw new System.IdentityModel.Tokens.SecurityTokenException("Bad Username or Password");
            }
        }
    }

--------------------------------------------------------------------------------------------------------

Client Web config

<system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="BasicHttpBinding_IService1">
                    <security mode="TransportWithMessageCredential" />
                </binding>
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint address="https://subhasissecureservice.com/Service1.svc"
                binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService1"
                contract="ServiceReference1.IService1" name="BasicHttpBinding_IService1" />
        </client>
</system.serviceModel>

--------------------------------------------------------------------------------------------------------

IIS Settings

Anonymous Authentication – Enabled
Basic Authentication – Enabled
Everything else – Disabled