Intranet – Web to Remote WCF Using Transport Security (Trusted Subsystem, TCP)

- J.D. Meier, Jason Taylor, Prashant Bansode, Carlos Farre, Madhu Sundararajan, Steve Gregersen

Applies To

  • Microsoft® Windows Communication Foundation (WCF) 3.5

Scenario

In this scenario, your users have Windows accounts and use a web client to connect over the intranet to an ASP.NET application on an IIS server. The ASP.NET application makes calls to the WCF service. The business logic called by the WCF service is backed by a SQL Server data store. The basic model for this application scenario is shown in the following figure.

Scenario1.JPG

Key Characteristics

This scenario applies to you if:
  • Your users have browsers supporting Integrated Windows Authentication
  • Your user accounts are in Active Directory within a domain
  • Your user roles are Windows Groups
  • The business logic behind your WCF service does not require fine-grained authorization
  • Your application transmits sensitive data over the network that needs to be protected
  • A high performance connection between the ASP.NET application and the WCF service is more important than the ability to host the WCF service in IIS

Solution

Solution1.JPG

Solution Summary Table

In this solution you will:
  • Use domain credentials to authenticate clients against an Active Directory user store
  • Use a service account to call WCF from the ASP.NET application
  • Use a service account to call the SQL Server from WCF
  • Use SSL to protect sensitive data between the web client and IIS
  • Use Transport security to protect sensitive data between the ASP.NET application and the WCF service
  • Use netTcpBinding to support the TCP transport for improved performance
  • Host WCF in a Windows Service since IIS does not support the TCP transport

Web Server

What Checks Example More Info
IIS
Configuration A dedicated application pool is used and configured to run under a custom service account. Use a domain account if possible.
The web application is configured to run under the service account. Assign the web application to the custom application pool.
Service Principal Name is created if domain identity is used in the ASP.NET application pool setspn -a HTTP//WebServer.domain.com customDomainAccount setspn -a HTTP//WebServer customDomainAccount Create an SPN for both the DNS and NETBIOS machine name.
Authentication The IIS virtual directory is configured to use Windows Integrated Authentication. Users will be authenticated with Windows authentication.
Anonymous access is disabled.
ASP.NET
Authentication ASP.NET is configured for Windows Integrated authentication <authentication mode = "Windows" > The web application will authenticate the users.
Authorization If you have role segmentation in your application then use URL authorization. <authorization> <allow roles="domainName\RoleName" /> <deny users="*" /> </authorization> The authorized users have access to specific pages
Role manager is enabled and Role-checks are performed role manager API <roleManager enabled="true" defaultProvider= "AspNetWindowsTokenRoleProvider"/> Original users are authorized using the windows groups before calling in WCF Service.
WCF Proxy
Configuration ASP.NET has a proxy reference to the WCF service. WCFTestService.MyServiceClient proxy = new WCFTestService.MyServiceClient(); The application has access to the WCF metadata to create a service reference.
Proxy invokes services with the security context ASP.NET process identity proxy.GetData("data"); proxy.Close(); The proxy will automatically invoke WCF operations using the security context of the service account.
Caller Identity For auditing purposes, the identity of the caller can be passed in custom message headers. using ( OperationContextScope scope = new OperationContextScope(proxy.InnerChannel)) { string identity = ((WindowsIdentity)HttpContext.Current.User.Identity).Name; MessageHeader<string> headerIdentity = new MessageHeader<string>(identity); MessageHeader untypedMessageHeader = headerIdentity.GetUntypedHeader("identity", "ns"); OperationContext.Current.OutgoingMessageHeaders.Add(untypedMessageHeader); TextBox1.Text = proxy.GetData("data");} Use transport security to protect against spoofing attacks

Application Server

What Checks Example More Info
Windows Service
Configuration Windows Service is configured to run under a custom domain service account Use a domain account if possible.
WCF service is hosted in windows service Since IIS does not support netTcpBinding, host in Windows Service
WCF Service
Configuration Configure the WCF service to use netTcpBinding. <service behaviorConfiguration="BehaviorConfiguration" name="WCFServicecHost.MyService" <endpoint address="" binding="netTcpBinding" bindingConfiguration="" name="TcpBinding" contract="WCFServicecHost.IMyService" /> <host> <baseAddresses> <add baseAddress="net.tcp://WCFApp01.npscode.com/MyService" /> </baseAddresses> </host> </service> The NetTcpBinding uses the TCP protocol and provides full support for SOAP security, transactions, and reliability. As client and WCF service both are in intranet this is a good choice from performance perspective.
A mex endpoint is created for publishing the metadata <services> <service behaviorConfiguration="BehaviorConfiguration" name="WCFServicecHost.MyService"> <endpoint address="Mex" binding="mexTcpBinding" bindingConfiguration="" name="MexEndpoint" contract="IMetadataExchange" /> </service> This is required so that client can add reference to the WCF Service using SvcUtil utility.
Service Metadata is configured in service behavior <behaviors> <serviceBehaviors> <behavior name="BehaviorConfiguration"> <serviceMetadata /> </behavior> </serviceBehaviors> </behaviors> The service metadata entry is required for the windows service host to start. The HTTP and HTTPS get are disabled
Authentication The netTcpBinding is configured to use Windows Authentication and Transport security. <endpoint address="" binding="netTcpBinding" bindingConfiguration=" " netTcpBinding by default supports Windows Authentication and Transport Security.
Caller Identity Service retrieves the identity of the caller from the operationcontext For auditing purposes string identity = OperationContext.Current.IncomingMessageHeaders.GetHeader<string>("identity", "ns"); Use the identity to improve logging and auditing
SQL The connection string for database is configured to use windows authentication SqlConnection sqlcon = new SqlConnection("Server=10.3.19.11;Database=Northwind;IntegratedSecurity=SSPI"); The database connection string includes Integrated Security=SSPI or Trusted Connection=Yes
Database connection is opened using the WCF process identity’s security context. Service does not impersonate the original caller to benefit for connection pooling

Database Server

What Check Example More Info
Configuration A SQL Server login is created for the WCF’s service account (process identity). exec sp_grantlogin 'Custom Service Account' This grants access to the SQL Server.
The login is mapped to a database user for the Web application. use targetDatabase go exec sp_grantdbaccess ' Custom Service Account' go This grants access to the specified database.
A database role is created in the target database. use targetDatabase go exec sp_addrole 'DB Role Name' go This allows access control and authorization to the DB.
The login is added to the database role. use targetDatabase go exec sp_addrolemember 'DB Role Name', 'Custom Service Account' go Grant minimum permissions. For example grant execute permissions to selected stored procedures and provide no direct table access.
Authentication SQL Server is configured to use Windows authentication.

Communication Security

What Check Example More Info
Browser to Web Server SSL is used between browser and Web server to protect sensitive data on the wire. Install certificate in the Web site. Configure the virtual directory of the web application to use SSL
App server to Database IPSec or SSL can be used between App server and database server to protect sensitive data on the wire.

Analysis

Web Server

Authentication
  • To prevent unauthenticated and unauthorized users from accessing pages anonymous access is disabled in IIS
  • Integrated Windows authentication is a good choice for this scenario because all users have Windows accounts. Integrated Windows authentication gives the benefit of keeping the user's password from ever being sent over the network. Additionally, the logon is transparent for the user because Windows uses the current user's logon session.
Authorization
  • URL authorization is used to perform role checks against the original caller and restrict access to pages based on role permissions.
  • All authorization checks are performed in the web application before calls are made to the WCF service. The WCF service trusts the web application to perform this authorization and does not need to make fine-grained authorization decisions of its own.
  • The Roles Manager is a good choice for this scenario because it allows your service code to look up users' roles without writing and maintaining custom code.
WCF Proxy
  • Because we are taking care of all authentication and authorization in the ASP.NET application, all calls through the WCF proxy and into the WCF service are made using the ASP.NET process identity’s security context. We don’t need to flow the original caller into the WCF service.
  • If we had needed to produce audit logs showing what service operations were called by each user we could have passed the identity of the original caller in a custom header.
Configuration
  • In order to reduce attack surface and minimize the impact of a compromise, the ASP.NET application on the Web Server is running under the security context of the Service account using a least privileged account.

Application Server

Authentication
  • In order to authenticate the ASP.NET service when it makes calls on the WCF Service, WCF is configured to use Windows Authentication.
Authorization
  • Since the WCF service trusts the ASP.NET application to authorize the user, no authorization is done in the WCF service.
SQL
  • To reduce the chances of database credentials being stolen, the database connection string is configured to use Windows authentication. This choice avoids storing credentials in files and passing credentials over the network to the database server.
  • The WCF service accesses the database using the WCF process identity. As a result, all calls are made using the single process account and database connection pooling to be used.
Configuration
  • This scenario is optimized around transmission performance at the expense of interoperability with clients that expect a legacy web service and the ability to host the service in IIS. For this reason the best binding choice is netTcpBinding. By default, netTcpBinding supports Windows Authentication with Transport security.
  • Because netTcpBinding is not supported by IIS 6.0, the WCF service is hosted in a windows service,
  • In order to reduce attack surface and minimize the impact of a compromise, the Windows service is running under the security context of the Service account using a least privileged account.
  • A metadata exchange (mex) endpoint is exposed to make it possible for the client to generate a proxy based on the service definition.

Database Server

  • SQL Server database user roles are preferred to SQL server application roles to avoid the associated password management and connection pooling issues associated with the use of SQL application roles. Applications activate SQL application roles by calling a built-in stored procedure with a role name and a password. Therefore, the password must be stored securely. Database connection pooling must also be disabled when you use SQL application roles, which severely impacts application scalability.
  • Creating a new user-defined database role and adding the database user to the role, allows you give specific minimum permissions to the role, so that if the database account changes; you don't have to change the permissions on all database objects.

Communication Security

  • SSL is used between browser and Web server to protect sensitive data on the wire.
  • Transport security is used to protect sensitive data between Web Server and App Server.
  • IPSec or SSL can be used between App server and database server to protect sensitive data on the wire.

Example

Domain Controller

Configuration
A service principle name (SPN) is created based on these rules:

If the ASP.NET application runs in an application pool with a custom domain identity, create an SPN and map the custom domain identity with the HTTP service class and both the DNS machine name and the NETBIOS machine name:
  • setspn -a HTTP//WebServer.domain.com customDomainAccount
  • setspn -a HTTP//WebServer customDomainAccount

If the WCF application runs in an application pool with a custom domain identity, create an SPN and map the custom domain identity with the HTTP service class and both the DNS machine name and the NETBIOS machine name:
  • setspn -a HTTP//WCFServer.domain.com customDomainAccount
  • setspn -a HTTP//WCFServer customDomainAccount

Web Server

Code
  • Role-authorization occurs before WCF service invocation
  • ASP.NET calls WCF service if it is authorized
  • Identity of the original caller is retrieved from the HttpContext
  • Message Header containing the caller identity is created and passed to the operation context for auditing purposes
using System.Security.Principal;
using System.ServiceModel;
using System.ServiceModel.Channels;
…
protected void Button1_Click(object sender, EventArgs e)
 {
*     if (Roles.IsUserInRole(@"npscode\Accounting"))*
     {
            WCFTestclient.MyServiceClient proxy = new WCFTestclient.MyServiceClient();
*using ( OperationContextScope scope = new OperationContextScope(proxy.InnerChannel))*
            {
*                string identity = ((WindowsIdentity)HttpContext.Current.User.Identity).Name;*
*                MessageHeader<string> headerIdentity = new MessageHeader<string>(identity);*
*                MessageHeader untypedMessageHeader = headerIdentity.GetUntypedHeader("identity", "ns");*
*                OperationContext.Current.OutgoingMessageHeaders.Add(untypedMessageHeader);*
                proxy.GetData("data");          
            }
            proxy.Close();
     }
 }

Configuration
  • Windows authentication is enabled
  • URL authorization role check is enabled
  • Role Manager is enabled
<system.web>
          <assemblies>
            <add assembly="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
            <add assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
            <add assembly="System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
            <add assembly="System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
          </assemblies>

*      <authentication mode="Windows" />*
*      <authorization>*
*        <allow roles="npscode\BusinessDivision" />*
*        <deny users="*" />*
*      </authorization>*

*      <roleManager enabled="true"*
*             defaultProvider= "AspNetWindowsTokenRoleProvider"/>*

      <pages>
        <controls>
          <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
          <add tagPrefix="asp" namespace="System.Web.UI.WebControls" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
        </controls>
      </pages>
      <httpHandlers>
        <remove verb="*" path="*.asmx"/>
        <add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
        <add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
        <add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" validate="false"/>
      </httpHandlers>
      <httpModules>
        <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
      </httpModules>
</system.web>

Application Server

Code
  • The service retrieves the identity of the caller from the operation context if it is required for auditing purposes
  • The service calls SQL using the security context of the WCF service
using System.Data.SqlClient;


  public string GetData(string myValue)
  {
 
      SqlConnection sqlcon = new SqlConnection("Server=SqlServer;Database=testdb;Integrated Security=SSPI");
*      sqlcon.Open();*
	//do the business operation	
      *string identity = OperationContext.Current.IncomingMessageHeaders.GetHeader<string>("identity", "ns");*
      return “some data” ;

   }

Configuration
  • The service has a binding endpoint that uses netTcpbinding with the default settings
  • The service has a service behavior configuration to publish metadata
  • The service has a base address configured
  • The service behavior is configured with element serviceMedata to allow metadata exposure
    <system.serviceModel>
        <behaviors>
            <serviceBehaviors>
                <behavior name="BehaviorConfiguration">
                    *<serviceMetadata />*
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <bindings />
        <services>
            <service behaviorConfiguration="BehaviorConfiguration" name="WCFServicecHost.MyService">
*                <endpoint address="Mex" binding="mexTcpBinding" bindingConfiguration=""*
*                    name="MexEndpoint" contract="IMetadataExchange" />*
*                <endpoint address="" binding="netTcpBinding" bindingConfiguration=""*
*                    name="TcpBinding" contract="WCFServicecHost.IMyService" />*
                <host>
                    <baseAddresses>
*                        <add baseAddress="net.tcp://perfpres02.npscode.com/MyService" />*
                    </baseAddresses>
                </host>
            </service>
        </services>
    </system.serviceModel>

Database Server

Configuration**
  • A SQL server login is created for the WCF service account
  • The WCF login name is given access to the database
  • The role is created in the database
  • The WCF login name is added to the role
-- Create a SQL Server login  that matches the WCF machine name
EXEC SP_GRANTLOGIN 'npscode\perfpres02$'

-- Grant the login access to the application database
use testdb 
go 
exec sp_grantdbaccess 'npscode\perfpres02$' 

-- Create the new database role
use testdb
go
exec sp_addrole 'myrole2','db_owner' 

-- Add the new login to the role
use testdb
go
exec sp_addrolemember 'myrole2','npscode\aspnethost' 


Contributors and Reviewers

  • External Contributors and Reviewers:
  • Microsoft Consulting Services and PSS Contributors and Reviewers:
  • Test team: Rohit Sharma, Chaitanya Bijwe, Parameswaran Vaideeswaran.
  • Edit team: Dennis Rea.
  • SEO team: Rob Boucher.

Last edited Jun 13, 2008 at 6:33 AM by rboucher, version 5

Comments

minsou Apr 29, 2009 at 9:50 AM 
I found the solution, you must call your service method in the OperationContextScope (inside the using statement)

minsou Apr 29, 2009 at 9:39 AM 
Hello Omedius, I have exactly the same problem, did you find a solution (I use WssHttpBinding) ?

Thanks

Omedius Jul 18, 2008 at 6:15 AM 
Hello,
I am trying to implement exactly the same scenario.
Seems that I do everything like described here, but when I am trying to access my header on the WCF service side, I get the following exception: "There is not a header with name identity and namespace ns in the message. I have attached the header as it is described here in this article in my web application.
I tried to change the names of the header and from the namespace both in my application and in WCF service, but still exactly the same error message is shown.
Could you please assist with this?
Any help is appreciated.