Mitigating Cross-Site Request Forgery (CSRF) Attacks

Cross-site request forgery (CSRF) is a Web application or Web service attack. An unsuspecting victim is tricked into performing an unintended action on behalf of an attacker on a Web site on which the victim is signed in as a legitimate, trusted user.

Typically, the attacker sends the victim a link or places an image element on the targeted Web site. When the victim follows the link or loads the image, the victim unknowingly initiates a malicious request hidden in the loaded page or image. If the victim is still signed in to the targeted Web site and the browser session cookie has not expired, the malicious request uses the identity and privileges of the victim, such as the victim’s browser session cookie, authentication credentials, internet protocol (IP) address, and Windows domain credentials, to pass as the victim and perform malicious actions, such as changing a password, changing contact information, or purchasing items. In this type of attack, the Web site cannot distinguish between the legitimate actions of the victim and the malicious actions of the attacker.

CSRF attacks exploit the trust between a Web site and the browser of an authenticated user. Web applications or services that store user authentication information in cookies are vulnerable to CSRF attacks.

Microsoft Commerce Server 2009 R2 introduces a commerce session token to mitigate the risk of cross-site request forgery (CSRF) attacks. By default, the CommerceSession is turned on in Web.config for the presentation tier routing service in the internal zone. However, the routing service is not enabled by default in the external zone. Therefore, if you do decide to support a RIA in the external zone and enable the routing service, you should also enable the CommerceSession.

The commerce session token is an encrypted session token issued to the Web services client, such as the Silverlight application, by the WCF-based routing service in response to a client request. Only a client logged in on the same domain or site of origin as the routing service can read the commerce session token because the browser in which the Silverlight application runs enforces the Same Origin Policy (SOP). This policy restricts cross domain requests; by default, the Silverlight application can only make requests to and receive responses from the Web service of the host site from which the Silverlight application was downloaded.

After the initial logon by the user, the Silverlight client sends a request accompanied by a browser cookie to the routing service. In response, the routing service declines the request because the commerce session token is absent. The routing service sends the declined response including a newly generated commerce session token to the client. Since the Silverlight client is in the same domain as the routing service, the Silverlight client can read the commerce session token. The Silverlight client reissues the request with the commerce session token, again accompanied by a browser cookie, to the routing service. If the commerce session token is valid, the routing service forwards the request to the Commerce Foundation to process the request; if the commerce session token is absent, expired or invalid, the routing service does not forward the request to the Commerce Foundation. Instead the routing service sends a failure response including a newly generated commerce session token.

Hh567689.edb327d4-d654-4b82-a591-e4fee655b04e(en-us,CS.95).gif

In the case of a cross-site request forgery attack, the user opens a Web page in a different page of the same browser. The loaded page contains a malicious script from a third party domain. Since the user is still signed in to the targeted Web site and the browser session cookie has not expired, the script runs and sends a request to the routing service without a commerce session token. Since there is no commerce session token, the routing service declines the request and issues a response with a commerce session token. However, the response including the corresponding commerce session token is sent to the Silverlight client because the browser enforces the same origin policy. The cross-site request forgery attack fails because the routing service ice never forwarded the request to the Commerce Foundation, so the request containing the malicious script was not executed. In addition, the malicious script cannot reissue the request with a valid commerce session token. The script cannot read the response and accompanying commerce session token since the script originates from a domain other than that of the routing service.

Hh567689.ddc8c33e-dd06-4860-9749-bbfa86996c9a(en-us,CS.95).gif

The commerce session token mitigates cross-site request forgery attacks for several reasons:

  • The commerce session token is a hash-based message authentication code (HMAC) dynamically generated by the routing service. It is unique to the user, limited in lifetime, and unpredictable to attackers.

  • Since the commerce session token is not propagated by the browser to the routing service, but rather by the Silverlight client, an attacker cannot borrow a valid commerce session token to include in a CSRF attack.

  • Since the browser in which the Silverlight application runs enforces the same origin policy, the commerce session token can only be read by a client in the same domain as the Windows Communication Foundation-based routing service. CSRF attacks originate outside the domain of the targeted site.

As a prerequisite to using the commerce session token, you must identify the user in some way. For example, the user can be identified with an anonymous user ID, a registered user ID, or a Windows user ID. You must have a post-authentication module in place that affirms the identity of the commerce user.

By default, the CommerceSession is turned on in Web.config for the presentation tier routing service in the internal zone. However, the routing service is not enabled by default in the external zone. Therefore, if you do decide to support a RIA in the external zone and enable the routing service, you should also enable the CommerceSession:

Commerce Foundation client-side configuration
<CommerceRouter
            operationServiceName="IOperationService"
            anonymousAccessOperationServiceName="IOperationService"
            enableProxyCaching="true">
            useHttpContextPrincipal ="true">
      <CommerceSession 
              enabled="true" 
              durationInMinutes="20"
              encryptionKey="{some very very long random string}" />
</CommerceRouter>

By default, the commerce session token uses the encryption key specified in the appSettings section of Web.config as the secret key. Prior to deployment, it is highly recommended that you specify a unique encryption key for use as the secret key.

You can specify your own secret key in one of the following ways:

  • Update the key specified in the appSettings section of the Web.config settings, as shown below:

   <appSettings>
       <add key="Encryption.Key" value="06020…" />

OR

  • Specify the secret key in the CommerceSession section, as shown below:

    <CommerceSession
             enabled="true"
           durationInMinutes="20"
        encryptionKey="0702…” />

If an encryption key is specified in both locations, the key specified in the CommerceSession takes precedence.

You can customize the commerce session token properties listed in the table below. By default, the settings for the commerce session token are as follows:

Property

Description

Possible Values

Required

Default Value

enabled

Specifies whether the commerce session token is turned on or off

true

false

Yes

true

durationInMinutes

Indicates the interval in minutes before the commerce session token expires

Positive Integer

Hh567689.alert_note(en-us,CS.95).gifNote:
For security reasons, this should be a short interval.

Yes

20

Encryption.Key

Specifies the secret key used in combination with other parameters to create the commerce session token

The Encryption.Key specified in the appSetting section of the Web.config settings

OR

Unlimited combination of user-specified alphanumeric characters in the CommerceSession section of the Web.config settings

Hh567689.alert_note(en-us,CS.95).gifNote:
For a strong cypher, the key must be 300 or more alphanumeric characters.

Yes (in one location or the other)

Encryption key specified in the appSetting section of the Web.config settings

As a best practice, recycle encryption keys at regular intervals as recommended by your business plan. To avoid cancelling open commerce transactions that use existing encryption keys, recycle encryption keys as part of your server maintenance routine.

For assistance recycling encryption keys, use the Profile Key Manager.

By default, session faults are not logged. Session faults occur routinely. For example, an initial request from the RIA client never includes a Commerce Session Token, so a no session fault exception always results. If you want to turn on SessionsFaults logging, you must uncomment out the lines that disable the logging for the SessionFaults in Web.config.

<server>
      <CommerceExceptionHandling defaultPolicyName="Default">
        <ExceptionPolicy name="Default">
         ………..
          <!-— <ExceptionHandler name="TextLoggingExceptionHandler" type="Microsoft.Commerce.Server.TextLoggingExceptionHandler, Microsoft.Commerce.Server, Version=9.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" initializeData="Microsoft.Commerce.SessionsFaults" /> -->
        </ExceptionPolicy>
      </CommerceExceptionHandling>
      ......
    </server>
   
<system.diagnostics>
    <sources>
<source name="Microsoft.Commerce.SessionsFaults" switchValue="Information">
         <listeners>
          <add name="SessionTokenEventLogListener"
               type="System.Diagnostics.EventLogTraceListener"
               traceOutputOptions="None"
               initializeData="Commerce Server SessionToken Log">
            <filter type="System.Diagnostics.EventTypeFilter" initializeData="All" />
          </add>
        </listeners>
     </source>
  </sources>
</system.diagnostics>

In the configuration above, the TextLoggingExceptionHandler points to the trace source Microsoft.Commerce.SessionsFaults via its initializeData attribute. The output from the Microsoft.Commerce.SessionsFaults is monitored by the listener SessionTokenEventLogListener and logged to the Commerce Server SessionToken log.

You have the option of logging faults as text to the event log using the TextLoggingExceptionHandler or as XML to a file using the XmlLoggingExceptionHandler. If you turn on SessionFault logging, the session faults are logged as text to the Commerce Server SessionToken log by default.

If you want to log session faults as XML to a file, make the following changes to the configuration:

Element and Attribute

Attribute Value

ExceptionHandler name

XMLLoggingExceptionHandler

ExceptionHandler type

XMLLoggingExceptionHandler

Listeners type

System.Diagnostics.TextWriterTraceListener

Listeners initializeData

The full path to the file

For more information about exception handling, see Logging, Tracing and Exception Management in Commerce Foundation.

In the following situation, you must create your own routing service client to propagate the commerce session token:

  • Your RIA client is not a Microsoft Silverlight or ASP.NET application, and

  • You want to use commerce session tokens to mitigate CSRF attacks

In this case, you must propagate the commerce session token yourself by writing your own software code.

As shown in the following figure, your routing service client must do the following:

  • Retrieve the commerce session token from every routing service response

  • Propagate the commerce session token to the next RIA client request

  • Handle session faults, specifically no session faults and expired session faults

Hh567689.a574b588-6e3f-45e9-a05c-c8020df937cf(en-us,CS.95).gif

In the case of an expired commerce session token, the routing service sends an expired session fault message with a valid commerce session token in the message header. The RIA client receives the response, extracts the valid commerce session token from the response, adds the valid commerce session token to the message header of the next request, and resends the request.

The following shows an example of a response from the routing service with a commerce session token:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
   <CommerceSessionTokenxmlns="http://schemas.microsoft.com/Commerce/2009/06/soap/headers">75C8660C0D69D1041FA9D9692D32850FA944DC6F837BF9684B5A460443C6898F20100920162655</CommerceSessionToken>
  </s:Header>
  <s:Body>
    <s:Fault>
      <faultcode>s:Client</faultcode>
      <faultstring xml:lang="en-CA">The creator of this fault did not specify a Reason.</faultstring>
      <detail>
        <CommerceNoSessionFault xmlns="http://schemas.microsoft.com/microsoft-multi-channel-commerce-foundation/types/2009/06" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
          <ExceptionDetails i:nil="true"/>
          <Message>The request to the routing service is missing a session token.</Message>
        </CommerceNoSessionFault>
      </detail>
    </s:Fault>
  </s:Body>
</s:Envelope>

The following shows a request from the RIA client with the commerce session token propagated from the response above to this request:

  <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Header>
     <CommerceSessionTokenxmlns="http://schemas.microsoft.com/Commerce/2009/06/soap/headers">75C8660C0D69D1041FA9D9692D32850FA944DC6F837BF9684B5A460443C6898F20100920162655</CommerceSessionToken>
    </s:Header>
    <s:Body>
      <ProcessRequest xmlns="http://schemas.microsoft.com/microsoft-multi-channel-commerce-foundation/types/2009/06">
        <request xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
           … rest of request
        </request>
      </ProcessRequest>
    </s:Body>
  </s:Envelope>
Show: