Chapter 14: Internet - Web to Remote WCF Using Transport Security (Trusted Subsystem, TCP)

patterns & practices Developer Center

Applies To

  • Microsoft® Windows Communication Foundation (WCF) 3.5

Scenario

In this scenario, your users do not have Windows accounts and use a Web client to connect over the Internet to an ASP.NET application on an Internet Information Services (IIS) server. The business logic called by the WCF service is backed by a Microsoft SQL Server® data store. The basic model for this application scenario is shown in the following figure.

Ff650091.CH14-Fig1(en-us,PandP.10).png

Figure 1
Web to Remote WCF Using Transport Security (Trusted Subsystem, TCP) – Model

Key Characteristics

This scenario applies to you if:

  • Your users have Web clients.
  • Your user accounts are stored in SQL Server.
  • Your user roles are stored in SQL Server.
  • 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

Ff650091.CH14-Fig2(en-us,PandP.10).png

Figure 2
Web to Remote WCF Using Transport Security (Trusted Subsystem, TCP) – Solution

Solution Summary Table

In this solution, you will:

  • Use a username and password to authenticate users against the SQL Server membership provider.
  • Use a service account to call WCF from the ASP.NET application.
  • Use a service account to call the SQL Server from WCF.
  • Use Secure Sockets Layer (SSL) encryption 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 Transmission Control Protocol (TCP) transport for improved performance.
  • Host WCF in a Windows service because IIS does not support the TCP transport.

Web Server

Checks / more information

IIS—cConfiguration

A dedicated application pool is created 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.

IIS—authentication

The IIS virtual directory is configured to use Anonymous access.

Users will be allowed to access pages and, if required, will be redirected to the Forms authentication page.

Checks / more information

Example

ASP.NET—configuration

An ASP.NET database is created for the SQL Server membership provider and SQL server role provider.

Aspnet_regsql.exe creates the SQL Server database to store the user and role information.

        
aspnet_regsql -S .\SQLExpress -E -A r m

      

The connection string is configured to point to the user and role store in SQL Server.

The database connection string includes Integrated Security=SSPI or Trusted Connection=Yes for Windows authentication.

        
<add name="MyLocalSQLServer" connectionString="Initial Catalog=aspnetdb;data source=localhost;Integrated Security=SSPI;" />

      

Web application process identity is given access permissions on the ASP.NET database.

Your Web application process identity requires access to the aspnetdb database. If you host the Web application in IIS 6.0 on Microsoft Windows Server® 2003, the NT AUTHORITY\Network Service account is used by default to run the Web application.

        
-- Create a SQL Server login for the Web application process identity
sp_grantlogin 'Customdomainserviceaccount

-- Grant the login access to the membership database USE aspnetdb GO sp_grantdbaccess 'Customdomainserviceaccount', 'Custom Service'

-- Add user to database role USE aspnetdb GO sp_addrolemember 'aspnet_Membership_FullAccess', 'Custom Service'

sp_addrolemember 'aspnet_Roles_FullAccess', 'Custom Service'

ASP.NET—authentication

ASP.NET is configured for Forms authentication.

The Web application will authenticate the users.

        
<authentication mode = "Forms" >

      

ASP.NET application is configured to deny access to all unauthenticated users.

Only authenticated users will be able to access the application.

        
<authorization>
   <deny users="?"/>
   <allow users="*"/>
</authorization>

      

SqlMembershipProvider is configured to use the membership feature for Forms authentication.

The membership feature helps protect credentials, can enforce strong passwords, and provides consistent APIs for user validation and secure user management. The membership feature also automatically creates the authentication ticket for you.

        
<membership defaultProvider="MySqlMembershipProvider">
    <providers>
       <clear/>
       <add name="MySqlMembershipProvider"   
       connectionStringName="MyLocalSQLServer" 
       applicationName="MyAppName"
       type="System.Web.Security.SqlMembershipProvider"/>
   </providers>
</membership>

      

ASP.NET—authorization

The Role Manager feature is enabled and SqlRoleProvider is configured for roles authorization.

The Role Manager feature allows you to look up users’ roles without writing and maintaining code. Additionally, the role providers offer a consistent way for you to check the role membership of your users, regardless of the underlying data store.

        
<roleManager enabled="true" defaultProvider="MySqlRoleProvider" >
    <providers>
      <clear/>
      <add name="MySqlRoleProvider"
           connectionStringName="MyLocalSQLServer"
           applicationName="MyAppName"
           type="System.Web.Security.SqlRoleProvider" />
    </providers>
</roleManager>

      

Role checks are performed using Role Manager APIs.

        
if (User.IsInRole("Role"))
{
   //business operation

}

Checks / more information

Example

WCF proxy

ASP.NET has a proxy reference to the WCF service.

The application has access to the WCF metadata in order to create a service reference.

        
WCFTestService.ServiceClient myService = new
WCFTestService.ServiceClient();

      

The proxy invokes services using the security context of service account.

The proxy will automatically invoke WCF operations using the security context of the service account.

        
myService.GetData(123);

      

WCF proxy—caller identity

For auditing purposes, the identity of the caller can be passed in custom message headers during the proxy call. Additionally, custom headers can be defined in message contracts or service contracts.

Use transport security to protect against spoofing attacks.

        
if (User.IsInRole("accounting"))
 {
  WCFTestService.MyServiceClient proxy = new      
  WCFTestService.MyServiceClient();
  using (OperationContextScope scope = new  
            OperationContextScope(proxy.InnerChannel))
    {
    string identity = 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();

Application Server

Checks / more information

Windows service—configuration

The Windows service is configured to run under a custom domain service account.

Use a domain account if possible.

The WCF service is hosted in a Windows service.

Because IIS does not support netTcpBinding, host it in Windows service.

Checks

Example

WCF service—configuration

Configure the WCF service to use netTcpBinding.

netTcpBinding uses the Transmission Control Protocol (TCP) and provides full support for Simple Object Access Protocol (SOAP) security, transactions and reliability. Because the client and WCF service are both located in an Intranet, this is a good choice from a performance perspective.

        
<endpoint address="" binding="netTcpBinding" bindingConfiguration="" name="TcpBinding" contract="WCFServicecHost.IMyService" />

      

A metadata exchange (mex) endpoint is created for publishing the metadata.

This is required so that the client can add a reference to the WCF service using the SvcUtil utility.

        
<endpoint address="Mex" binding="mexTcpBinding" bindingConfiguration=""
name="MexEndpoint" contract="IMetadataExchange" />

      

Service metadata is configured in the service behavior.

The service metadata entry is required for the Windows service host to start. Both HTTP and HTTPS GET requests are disabled.

        
<serviceMetadata />

      

WCF service—authentication

netTcpBinding is configured to use Windows authentication and transport security.

By default, netTcpBinding is configured to use Windows authentication and transport security.

        <
endpoint address="" binding="netTcpBinding" bindingConfiguration="" />

      

WCF service—caller Identity

The service retrieves the identity of the caller from the OperationContext for auditing purposes.

Use the identity to improve logging and auditing.

        
string identity = OperationContext.Current.IncomingMessageHeaders.GetHeader<string>("identity", "ns");

      

WCF service—SQL

The connection string for the database is configured to use Windows authentication.

The database connection string includes Integrated Security=SSPI or Trusted Connection=Yes.


The database connection is opened using the WCF process identity’s security context.

The service does not impersonate the original caller to benefit from connection pooling.

Database Server

Checks / more information

Example

Configuration

A SQL Server login is created for the WCF’s service account (process identity).

This grants access to the SQL Server.

        
exec sp_grantlogin 'Custom Service Account'

      

The login is mapped to a database user for the Web application.

This grants access to the specified database.

        
use targetDatabase 
go 
exec sp_grantdbaccess ' Custom Service Account' 
go

      

A database role is created in the target database.

This allows access control and authorization to the databse.

        
use targetDatabase 
go 
exec sp_addrole 'DB Role Name' 
go 

      

The login is added to the database role.

Grant minimum permissions. For example, grant execute permissions to selected stored procedures, and provide no direct table access.

        
use targetDatabase
go
exec sp_addrolemember 'DB Role Name', 'Custom Service Account'
go

      

Authentication

SQL Server is configured to use Windows authentication.

Communication Security

What

Checks

More Info

Browser to Web server

SSL is used between the browser and Web server to protect sensitive data on the wire.

Install a certificate in the Web site. Configure the virtual directory of the Web application to use SSL.

Application server to database server

You can use IPSec or SSL between the application server and the database server to protect sensitive data on the wire.

 

Analysis

Web Server

Authentication

  • Anonymous access in IIS is enabled to allow unauthenticated and unauthorized users to access pages and redirect to the login page.
  • Forms authentication is a good choice for this scenario because users come from the Internet and have accounts in SQL Server.
  • The Membership feature is a good choice to use with Forms authentication, as it allows you to authenticate users without writing and maintaining custom code.

Authorization

  • URL authorization performs role checks against the original caller and restricts access to pages based on role permissions.
  • All authorization checks occur in the Web application before it makes calls 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 Role Manager is a good choice for this scenario because it allows the application to look up users’ roles without writing and maintaining custom code.

WCF Proxy

  • Because you are taking care of all authentication and authorization in the ASP.NET application, all calls through the WCF proxy and into the WCF service use the ASP.NET process identity’s security context.
  • If you need to produce audit logs showing what service operations each user called, you can pass the identity of the original caller in a custom header.

Configuration

  • In order to reduce the attack surface and minimize the impact of a compromise, the ASP.NET application on the Web server runs under the security context of the service account, using a least-privileged account.

Application Server

Authentication

  • WCF is configured to use Windows authentication in order to authenticate the ASP.NET service when it makes calls into the WCF service.

Authorization

  • Because the WCF Service trusts the ASP.NET application to authorize the user, the WCF service performs no authorization.

Data Access

  • To reduce the risk of stolen database credentials, the database connection string is configured to use Windows authentication. This choice eliminates the need to store credentials in files and pass credentials over the network to the database server.
  • The WCF service accesses the database using the WCF process identity. As a result, all calls use the single process account and designated database connection pooling.

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 IIS 6.0 does not support netTcpBinding, the WCF service is hosted in a Windows service.
  • In order to reduce the 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 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 over SQL Server application roles to avoid the password management and connection pooling issues associated with the use of SQL Server application roles. Applications activate SQL Server application roles by calling a built-in stored procedure with a role name and a password. Therefore, you must store the password securely. You must also disable database connection pooling when you use SQL Server application roles, which severely impacts application scalability.
  • Creating a new user-defined database role and adding the database user to the role lets you give specific minimum permissions to the role. In this way, if the database account changes, you do not have to change the permissions on all database objects.

Communication Security

  • SSL protects sensitive data on the wire between the browser and Web server.
  • Transport security protects sensitive data between the Web server and application server.
  • You can use IPSec or SSL between the application server and database server to protect sensitive data on the wire.

Example

Web Server

Code

  • A form is created in order to perform Forms authentication.
  • Role authorization occurs before WCF service invocation.
  • ASP.NET calls the WCF service if it is authorized.
  • The original caller’s identity is retrieved from the user ticket context.
  • A message header containing the caller identity is created and passed to the operation context for auditing purposes.

The following code example shows a form that performs Forms authentication:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Login.aspx.cs" Inherits="Login" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head >
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" >
    <div>

    </div>
    <asp:Login ID="Login1"  >
    </asp:Login>
    <asp:CreateUserWizard ID="CreateUserWizard1" >
        <WizardSteps>
            <asp:CreateUserWizardStep  />
            <asp:CompleteWizardStep  />
        </WizardSteps>
    </asp:CreateUserWizard>
    </form>
</body>
</html>



//Proxy call invocation
using System.ServiceModel;
using System.ServiceModel.Channels;
…
protected void Button1_Click(object sender, EventArgs e)
 {
  if (User.IsInRole("accounting"))
  {
    WCFTestService.MyServiceClient proxy 
         = new WCFTestService.MyServiceClient();
    using (OperationContextScope scope 
         = new OperationContextScope(proxy.InnerChannel))
    {
     string identity = 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();

   } //endif

 } //end function

Configuration

  • Windows and anonymous authentication are enabled.
  • Connection strings to SqlMembershipProvider and SqlRoleProvider are configured.
  • SQLMembershipProvider is enabled.
  • Only authenticated users are allowed to browse the site.
  • Role Manager is enabled.
<configuration>
   …
<connectionStrings>
   <add name="MyLocalSQLServer" connectionString="Initial 
        Catalog=aspnetdb;data source=10.3.19.60;Integrated Security=SSPI;"/>
</connectionStrings>

<system.web>
  <membership defaultProvider="MySqlMembershipProvider">
     <providers>
  <clear/>
  <add name="MySqlMembershipProvider" 
             connectionStringName="MyLocalSQLServer" 
             applicationName="MyAppName" 
             type="System.Web.Security.SqlMembershipProvider"/>
</providers>
  </membership>

  <roleManager enabled="true" defaultProvider="MySqlRoleProvider">
<providers>
        <clear/>
  <add name="MySqlRoleProvider" 
             connectionStringName="MyLocalSQLServer" 
             applicationName="MyAppName" 
             type="System.Web.Security.SqlRoleProvider"/>
</providers>
  </roleManager>

  <authentication mode="Forms"/>
  <authorization>
    <deny users="?"/>
    <allow users="*"/>
  </authorization>

  <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 Server 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 the serviceMedata element 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' 

Additional Resources