Secure a TCP – WCF service at the Message level

When building and using WCF services to exchange messages over the wire, you must always take into account security. In one line, security is concerned with protecting users running client applications, services and the messages passing between them. These messages may contain private user information such as passwords, bank accounts credentials etc. Also, usually the service must ensure that the client is the one who claims to be and respectively, the client must know  that it’s messages are sent to the right destination service. This post will show you how to implement TCP message level security by encrypting messages exchanged between client and service.  In a previous post we saw how to host and consume a WCF service over TCP. We will configure NetTcpBinding binding in the Web.config file of the service to encrypt messages at the message level. NetTcpBinding automatically encrypts data at the transport level by using Transport Layer Security (TLS) over TCP. Adding security at the message level, gives you a greater degree of security. Configure netTcpBinding of your WCF service to encrypt messages at the message level as follows.

<?xml version="1.0"?>
<configuration>
  <connectionStrings>
    <add name="AdventureWorks2012Entities" connectionString="metadata=res://*/AdventureWorksModel.csdl|res://*/AdventureWorksModel.ssdl|res://*/AdventureWorksModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=developer-PC;initial catalog=AdventureWorks2012;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />
  </connectionStrings>
  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/>
  </appSettings>
  <system.web>
    <compilation debug="false" targetFramework="4.5">
      <assemblies>
        <add assembly="System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
      </assemblies>
    </compilation>
    <httpRuntime targetFramework="4.5"/>
  </system.web>
  <system.serviceModel>
    <bindings>
      <netTcpBinding>
        <binding name="AdventureWorksServiceTcpBindingConfig">
          <security mode="Message">
            <message algorithmSuite="Basic128" />
          </security>
        </binding>
      </netTcpBinding>
    </bindings>
    <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="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service name="AdventureWorks.AdventureWorksServiceImpl">
        <endpoint address="net.tcp://developer-pc/AdventureWorksService/Service.svc" binding="netTcpBinding"
                  bindingConfiguration="AdventureWorksServiceTcpBindingConfig" name="NetTcpBinding_AdventureWorksService"
                  contract="AdventureWorks.AdventureWorksService">
        </endpoint>
      </service>
    </services>
    <protocolMapping>
      <add binding="basicHttpsBinding" scheme="https"/>
    </protocolMapping>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
    <!--
        To browse web app root directory during debugging, set the value below to true.
        Set to false before deployment to avoid disclosing web app folder information.
      -->
    <directoryBrowse enabled="true"/>
  </system.webServer>
</configuration>

You can do that, straight forward in the Web.config file in you IIS folder. The netTcpBinding will now encrypt all messages using the Advance Encryption Standard (AES) 128-bit algorithm. This is a good and efficient encryption algorithm to use inside an organization. If you are sending messages over the Internet you may prefer to use the default algorithm, that is Basic256. Try to run the client application without making any changes yet. You should get an error like below.
securityex

This is normal though, since we told the service to encrypt messages before sending them to client, but we didn’t update client configuration to accept this kind of messages. At the moment, client expects normal and non-encrypted ones. So by the time he receives an encrypted message, an error will occur at some point in the channel’s stack processing. To resolve this, simply make the respective configurations in the App.config file of the client project as follows.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="BasicHttpBinding_AdventureWorksService" />
            </basicHttpBinding>
            <netTcpBinding>
              <binding name="NetTcpBinding_AdventureWorksService">
                <security mode="Message">
                  <message algorithmSuite="Basic128" />
                </security>
              </binding>
            </netTcpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost/AdventureWorksService/Service.svc"
                binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_AdventureWorksService"
                contract="AdventureWorksServiceRef.AdventureWorksService"
                name="BasicHttpBinding_AdventureWorksService" />
            <endpoint address="net.tcp://developer-pc/AdventureWorksService/Service.svc"
                binding="netTcpBinding" bindingConfiguration="NetTcpBinding_AdventureWorksService"
                contract="AdventureWorksServiceRef.AdventureWorksService"
                name="NetTcpBinding_AdventureWorksService">
                <identity>
                    <userPrincipalName value="developer-PC\developer" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>
</configuration>

That’s it. Now there is an agreement between client and service on how they exchange messages. Build and run the client project again. You should receive no errors this time.



Categories: WCF

Tags:

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: