Information
The topic you requested is included in another documentation set. For convenience, it's displayed below. Choose Switch to see the topic in its original location.

HTTP Communication and Security with Silverlight

Silverlight

Silverlight enables HTTP/HTTPS communication with Web services hosted both within and outside the domain that is hosting your Silverlight application. This topic discusses HTTP communication and security considerations for Silverlight application developers and Web service developers.

This topic contains the following sections:

In Silverlight, there are some basic capabilities for HTTP/HTTPS communication. The capabilities vary depending on whether you use the browser hosting the Silverlight application to perform the HTTP handling, or you opt to use the Silverlight client to perform the HTTP handling. For information about how to specify the HTTP handling for your applications, see How to: Specify Browser or Client HTTP Handling.

The following is a list of the basic HTTP capabilities and whether the capability is supported by browser or client HTTP handling:

Capability

HTTP Handling

Notes

Same domain calls

Browser or Client

Always allowed.

Cross-domain calls

Browser or Client

Allowed when it is configured per client access policy file hosted on server.

Asynchronous communication

Browser or Client

All calls are asynchronous.

Standard and custom headers

Browser or Client

Must be allowed per client access policy file.

GET and POST methods

Browser or Client

Always allowed.

Methods other than GET and POST

Client only

Only allowed with client HTTP handling.

Must be allowed per client access policy file.

200 OK and 404 Not Found status codes

Browser or Client

Always allowed.

Other status codes, response headers and response body

Client only

Always allowed.

REST service calls

Client only

Always allowed.

Automatic cookie handling

Browser only

Always allowed. Browser-based cookie store and client-based cookie store are separate and do not interoperate.

Manual access to cookie store

Client only

Always allowed. Browser-based cookie store and client-based cookie store are separate and do not interoperate.

Referer header sent with requests

Client always sends, Browser sometimes sends

Some browsers do not send Referer header with all requests.

Silverlight supports several scenarios that use HTTP/HTTPS. Although there are multiple ways and technologies that can be used to make HTTP calls, the following table describes recommended approaches for these HTTP communication scenarios. These approaches are discussed in more detail later in this topic.

Scenario

Recommended Approach

Download and upload resources in the same domain.

Use the WebClient class. For more information, see Downloading Content on Demand.

Call HTTP-based Web services hosted in the same domain.

Use the WebClient class or the HttpWebRequest/HttpWebResponse classes. For more information, see How to: Make Requests to HTTP-Based Services.

Call SOAP, WCF, or ASP.NET AJAX Web services hosted in the same domain.

Call the generated proxy for the Web service. For more information, see Accessing Services using Generated Proxies.

If you do not want to use a proxy, use the HttpWebRequest/HttpWebResponse classes.

Process XML, JSON, or RSS data from a Web service.

Use the WebClient class or the HttpWebRequest/HttpWebResponse classes. For more information, see Accessing HTTP Services Directly or How to: Load an XML File from an Arbitrary URI Location with LINQ to XML.

Call a Web service that is on a different domain.

Ensure a client access policy file is at the root of the domain. Use a proxy, the WebClient class, or the HttpWebRequest/HttpWebResponse classes. For more information, see How to: Make a Service Available Across Domain Boundaries.

Send PUT, DELETE and other HTTP methods, including custom methods.

Ensure the client access policy enables additional HTTP methods. Specify Client HTTP handling and use HttpWebRequest/HttpWebResponse classes as you ordinarily would. For more information about specifying Client HTTP handling, see How to: Specify Browser or Client HTTP Handling.

Set request headers on cross-domain POST requests.

Ensure the header is allowed per the client access policy file.

For request headers on data uploads, use the WebClient class. Set its Headers property to the desired header collection.

For other scenarios use the HttpWebRequest class. Set its Headers property to the desired header collection. For a list of allowed headers, see HttpWebRequest.Headers.

Send request headers with all methods.

Specify Client HTTP handling and use HttpWebRequest/HttpWebResponse classes as you normally would, setting the Headers property as needed.

Send requests to a SOAP service that returns error codes and SOAP faults

Specify Client HTTP handling and use HttpWebRequest/HttpWebResponse classes as you normally would, retrieving the message body in error situations. For more information about specifying client HTTP handling, see How to: Specify Browser or Client HTTP Handling.

Send GET requests to a Web service that requires a Referer header.

Specify Client HTTP handling and use HttpWebRequest/HttpWebResponse classes as you normally would. For more information about specifying client HTTP handling, see How to: Specify Browser or Client HTTP Handling.

Manually access the cookie store.

Specify Client HTTP handling and use HttpWebRequest/HttpWebResponse classes to get and set the CookieContainer and Cookies as needed. For more information, see How to: Get and Set Cookies.

Once you have decided whether the HTTP handling for your application should be performed by the browser or the client, you should specify the handling before creating any Web requests. You can then make HTTP calls by using a client-side proxy class or by constructing the calls yourself. This section describes the different options for making HTTP calls.

Note Note:

For information about how to specify the HTTP handling for your applications, see How to: Specify Browser or Client HTTP Handling.

Using Proxy Classes

If you are communicating with a SOAP, WCF, or ASP.NET AJAX Web service, you can create a proxy class from the Web service metadata and use the proxy to communicate with the Web service. Silverlight uses Windows Communication Foundation (WCF) capabilities to create proxies and send SOAP 1.1 messages over HTTP. If you are using Visual Studio, you can right-click your Silverlight project and select Add Service Reference to have the proxy automatically created for you. The proxy creates the messages and handles the network communication for you. For more information about how to create Web services to interact with Silverlight and how to generate proxies to use with existing Web services, see Building and Accessing Services using Generated Proxies.

You can also use the Add Service Reference dialog box in Visual Studio to add a reference to any service that exposes an Open Data Protocol (OData) feed. Silverlight is able to consume OData feeds by using the WCF Data Services client library for Silverlight. For more information about working with OData feeds in a Silverlight-based application, see WCF Data Services (Silverlight).

Creating HTTP Requests

If you want to make HTTP calls yourself, you can use the following classes found in the System.Net namespace.

These classes enable you to make GET and POST requests and allow request headers in some cases. In addition, you can configure these classes to enable progressive downloads on GET requests.

WebClient Class

The WebClient class provides a simple event-based model that enables you to download and upload streams and strings. The WebClient is a good choice if you do not want to use a proxy class. In general, this class is easy to use, but provides fewer options to customize messages that are sent across a network.

To make a POST request with WebClient and upload resource files or strings, you use one of the following methods.

You can set headers on requests by setting the WebClient.Headers property. Request headers must be allowed per the client access policy file. For more information, see the Cross-Domain Communication section of this topic.

The following code shows an example of making a POST request with WebClient.



	// Create the web client.
        WebClient client = new WebClient();
        public Page()
        {
            InitializeComponent();

	   // Associate the web client with a handler for its
	   // UploadStringCompleted event.
            client.UploadStringCompleted += 
                new UploadStringCompletedEventHandler(client_UploadStringCompleted);
        }



        private void Button_Click(object sender, RoutedEventArgs e)
        {
	   // Create the request. 
            string postRequest = "<entry xmlns='http://www.w3.org/2005/Atom'>"
            + "<title type='text'>New Restaurant</title>"
            + "<content type='xhtml'>"
            + "  <div xmlns='http://www.w3.org/1999/xhtml'>"
            + "   <p>There is a new Thai restaurant in town!</p>"
            + "   <p>I ate there last night and it was <b>fabulous</b>.</p>"
            + "   <p>Make sure and check it out!</p>"
            + "  </div>"
            + " </content>"
            + " <author>"
            + "   <name>Pilar Ackerman</name>"
            + "  <email>packerman@contoso.com</email>"
            + " </author>"
            + "</entry>";

	    // Sent the request to the specified URL.
            client.UploadStringAsync(new                 Uri("http://blogs.contoso.com/post-create?blogID=1234",
                UriKind.Absolute), postRequest); 
        }

        // Event handler for the UploadStringCompleted event.
        void client_UploadStringCompleted(object sender, 
           UploadStringCompletedEventArgs e)
        {
	    // Output the response. 
            if (e.Error != null)
                tb1.Text = e.Error.Message;
            else
                tb1.Text = e.Result;
        }



To make a GET request with WebClient to retrieve strings or other resource files, you use one of the following methods.

To enable progressive downloads for WebClient, set the AllowReadStreamBuffering property to false.

For more information about how to use WebClient to download content, see Downloading Content on Demand.

HttpWebRequest and HttpWebResponse Classes

The HttpWebRequest and HttpWebResponse classes support more complex communication scenarios than WebClient. You use HttpWebRequest and HttpWebResponse following the .NET Framework asynchronous pattern to make requests. You use an IAsyncResult to provide a connection between the asynchronous request and response. HttpWebRequest delegates are always called on a new non-UI thread, which means that if you plan to use the response in the UI, you will have to invoke back to the UI thread. You can do this by retrieving the current SynchronizationContext.

The following code example demonstrates the pattern you must use for making a call using the HttpWebRequest and HttpWebResponse classes.


SynchronizationContext syncContext;
private void Button_Click(object sender, RoutedEventArgs e)
{
    // Grab SynchronizationContext while on UI Thread   
    syncContext = SynchronizationContext.Current;

    // Create request   
    HttpWebRequest request =
        WebRequest.Create(new Uri("http://blogs.contoso.com/post-create?blogID=1234", 
            UriKind.Absolute))
            as HttpWebRequest;
    request.Method = "POST";


    // Make async call for request stream.  Callback will be called on a background thread.  
    IAsyncResult asyncResult =
        request.BeginGetRequestStream(new AsyncCallback(RequestStreamCallback), request);

}
string statusString;
private void RequestStreamCallback(IAsyncResult ar)
{
    HttpWebRequest request = ar.AsyncState as HttpWebRequest;
    request.ContentType = "application/atom+xml";
    Stream requestStream = request.EndGetRequestStream(ar);
    StreamWriter streamWriter = new StreamWriter(requestStream);

    streamWriter.Write("<entry xmlns='http://www.w3.org/2005/Atom'>"
    + "<title type='text'>New Restaurant</title>"
    + "<content type='xhtml'>"
    + "  <div xmlns='http://www.w3.org/1999/xhtml'>"
    + "   <p>There is a new Thai restaurant in town!</p>"
    + "   <p>I ate there last night and it was <b>fabulous</b>.</p>"
    + "   <p>Make sure and check it out!</p>"
    + "  </div>"
    + " </content>"
    + "<author>"
    + "   <name>Pilar Ackerman</name>"
    + "  <email>packerman@contoso.com</email>"
    + " </author>"
    + "</entry>");


    // Close the stream.
    streamWriter.Close();

    // Make async call for response.  Callback will be called on a background thread.
    request.BeginGetResponse(new AsyncCallback(ResponseCallback), request);

} 
private void ResponseCallback(IAsyncResult ar)  
{  
    HttpWebRequest request = ar.AsyncState as HttpWebRequest;
    WebResponse response = null;
    try
    {
        response = request.EndGetResponse(ar);
    }
    catch (WebException we)
    {
        statusString = we.Status.ToString();
    }
    catch (SecurityException se)
    {
        statusString = se.Message;
        if (statusString == "")
            statusString = se.InnerException.Message;
    }

    // Invoke onto UI thread  
    syncContext.Post(ExtractResponse, response);  
} 

private void ExtractResponse(object state)  
{  
    HttpWebResponse response = state as HttpWebResponse;

    if (response != null && response.StatusCode == HttpStatusCode.OK) 
    {
        StreamReader responseReader = new StreamReader(response.GetResponseStream());


        tb1.Text = response.StatusCode.ToString() + 
            " Response: "  + responseReader.ReadToEnd();
    }
    else
        tb1.Text = "Post failed: " + statusString;
}


You can send headers, if they are allowed per the client access policy file, by setting the HttpWebRequest.Headers property. If you are sending headers on anything other than POST requests, you must use Client HTTP handling. For more information, see the Cross-Domain Communication section of this topic.

To enable progressive downloads for HttpWebRequest, set the AllowReadStreamBuffering property to false. You can then make multiple calls to BeginRead on the response stream.

For more information about how to use HttpWebRequest and HttpWebResponse to communicate with a Web service, see How to: Make Requests to HTTP-Based Services.

By default, Silverlight supports calls to Web services on the same domain or site of origin. Same domain means that calls must use the same sub domain, protocol, and port. This is for security reasons and prevents cross-domain forgery.

The following illustration shows examples of calls that are allowed and not allowed in a Silverlight application that uses the default settings.

Allowed HTTP Communication for Default Settings

Silverlight default networking restrictions

Enabling Cross-Domain Communication by Using Cross-Domain Policy Files

You can enable Web services to be called by a Silverlight application in another domain by deploying a Web service that uses the correct cross-domain policy file at the root of the domain. Silverlight supports two types of cross-domain policy files.

  • Silverlight client access policy file (clientaccesspolicy.xml)

  • A subset of the Adobe Flash cross-domain policy file (crossdomain.xml)

The following illustration shows an example of cross-domain communication by using a client access policy file.

Cross-Domain Communication by using a Client access Policy File

Silverlight cross-domain policy

In general, when a Silverlight application detects that its request is a cross-domain request, it will first look for the Silverlight client access policy file (clientaccesspolicy.xml) at the application root of the Web service. If this request causes a 404 Not Found or other error, the application will then look for the Adobe Flash cross-domain policy file (crossdomain.xml) at the application root. Redirects for the cross-domain policy file are not allowed. In addition, the cross-domain policy file is requested only once per application session.

The following table lists example request Uniform Resource Identifiers (URIs) and where the Silverlight application will look for the cross-domain policy file.

Request URI

Cross-Domain Policy File Location

http://contoso.com/services/data

http://contoso.com/clientaccesspolicy.xml

http://sales.contoso.com/services/data

http://sales.contoso.com/clientaccesspolicy.xml

http://contoso.com:8080/services/data

http://contoso.com:8080/clientaccesspolicy.xml

https://contoso.com/services/data

https://contoso.com/clientaccesspolicy.xml

As mentioned previously, redirects on cross-domain policy files are not allowed. However, a Silverlight application will follow a redirect for a target resource. The resource can be retrieved only if access is granted by the following:

  • The cross-domain policy file at the domain indicated by the original URI before redirection.

  • The cross-domain policy file at the domain indicated by the final URI after all redirections.

Security Considerations for Web Services Exposed to Silverlight Cross-Domain Callers

There are important security considerations before you allow Silverlight clients to access Web services in a cross-domain situation. Whenever you put a client access policy file in place, you should configure your Web server hosting the Web services to disable browser caching. This enables you to easily update the file or restrict access to your Web services if necessary. Once the client access policy file is checked, it remains in effect for the browser session so the impact of non-caching to the end-user is minimal. 

If you provide HTTP and HTTPS sites for your domain, you should provide a client access policy specific to each protocol for the domain. In the client access policy file, you should only enable calls from the same protocol as the hosting domain. For example, if your domain is https://contoso.com, your policy file should only enable Silverlight clients using the HTTPS protocol like the following example.

<allow-from http-request-headers="*">
        <domain uri="https://fabrikam.com"/>
        <domain uri="https://www.adatum.com"/>
      </allow-from>

To prevent malicious attacks, you should never provide one client access policy file for HTTP and HTTPS versions of your domain that enable calls from both HTTP and HTTPS clients. For example, you should never do the following in a single client access policy file.

<!--DO NOT DO THIS-->
<allow-from http-request-headers="*">
        <domain uri="http://fabrikam.com"/> 
        <domain uri="https://fabrikam.com"/>
      </allow-from>

In addition, all Silverlight requests are sent with cookies and authentication. This means that if you have Web services that allow users to access private information, you should host these in a different domain than the Web services exposed to third-party callers. For example, consider that you have a Web store hosted at http://www.tailspintoys.com. Your site allows customers to store billing information that includes credit card numbers. You should not expose a Web service that returns product inventory to third-party Silverlight clients at the same domain. Because cookies and authentication are sent with each message, if you host these Web services on the same domain, you have effectively given the third-party callers access to your customer's private billing information. In this example, your publicly exposed Web services could safely be hosted at http://services.tailspintoys.com, because this is a different domain. You must carefully consider who you have exposed Web services to, and what other Web services are located at that domain. Also, you should always keep your client access policy file as restrictive as possible. For more information about exposing secure Web services, see Security Considerations for Service Access and Making a Service Available Across Domain Boundaries.

Client-Access Policy File Example

The Silverlight client access policy file is an XML file that has a simple format. The following example shows a Silverlight client access policy file. This example has two policy entries.

The first policy enables:

  • GET and POST requests from all callers to the services path of the domain.

  • SOAPAction Content-Type headers for all callers.

The second policy enables:

  • All method requests from the www.contoso.com domain to the services path. These callers must be using Silverlight 3 or later and must be client HTTP handling to make method calls other than GET and POST.

  • Does not allow headers on any calls

<?xml version="1.0" encoding="utf-8"?>
  <access-policy>
    <cross-domain-access>
      <policy>
        <allow-from http-request-headers="SOAPAction">
          <domain uri="*"/>
        </allow-from>
        <grant-to>
          <resource path="/services/" include-subpaths="true"/>
        </grant-to>
     </policy>
      <policy >
        <allow-from http-methods="*">
          <domain uri="http://www.contoso.com"/>
        </allow-from>
        <grant-to>
          <resource path="/services/" include-subpaths="true"/>
        </grant-to>
     </policy>
    </cross-domain-access>
  </access-policy>

A file may contain as many policy entries as necessary for a particular application root. Calls are allowed per a union of all the policy entries in the file. In this example, if a POST request including a SOAPAction header came from www.contoso.com, it would be allowed per the first policy. For more information on the format of the client access policy file, see Network Security Access Restrictions in Silverlight.

WildCard Character in the Silverlight Cross-Domain Policy File

The Silverlight client access policy file (clientaccesspolicy.xml) can contain a wildcard character (*). The wildcard character can be used to give all domains access to your services, but in general you should limit cross-domain access to a minimal set of domains that you know will require access. In addition, how you use the wildcard character affects communication between HTTP and HTTPS, or cross-scheme, callers, and services.

The following table lists the possible values for the domain node and the effect each value has during cross-scheme access.

URI

HTTPS

HTTP

<domain uri = "*">

Enables all HTTPS callers

Enables all HTTP and HTTPS callers

<domain uri= "http://*">

Enables all HTTP callers

Enables all HTTP callers

<domain uri = "http://www.contoso.com" >

Callers from http://www.contoso.com only

Callers from http://www.contoso.com only

<domain uri = https://www.contoso.com >

Callers from https://www.contoso.com only

Callers from https://www.contoso.com only

In addition, you can use the wildcard character to enable callers from specific sub-domains in the <AllowFrom> section of the client access policy file. The following example shows an excerpt of Silverlight client access policy file that uses the wildcard character to enable requests from a sub domain.

<?xml version="1.0" encoding="utf-8"?>
  <access-policy>
    <cross-domain-access>
      <policy >
        <allow-from http-request-headers="SOAPAction">
          <domain uri="http://*.tailspintoys.com"/>
        </allow-from>
...

Method Support for Cross-Domain Requests

You can enable additional HTTP methods for Silverlight applications by using client HTTP handling. You do this by setting the http-methods attribute to the wildcard character (*). If a Silverlight application is using browser HTTP handling, only GET and POST are enabled, regardless of the setting in the client access policy file. Some methods are restricted for security reasons.

<?xml version="1.0" encoding="utf-8"?>
  <access-policy>
    <cross-domain-access>
      <policy >
        <allow-from http-methods="*">
          <domain uri="http://*.tailspintoys.com"/>
        </allow-from>
...

Header Support for Cross-Domain Requests

With browser HTTP handling, request headers are permitted on cross-domain POST requests only when explicitly permitted in the client access policy file. Client HTTP handling enables request headers on all HTTP methods when permitted in the client access policy file. An exception to this rule is Content-Type headers. Content-Type headers are always allowed on cross-domain POST requests and do not need to be explicitly called in the client access policy file. You can also enable additional headers by setting http-request-headers to one of the following:

  • A single header type (SOAPAction)

  • A comma separated list of headers (SOAPAction, x-custom-header)

  • The wildcard character to enable all headers (*)

Note Note:

For security reasons, Silverlight blocks SOAPAction headers that contain Universal Plug and Play (UPnP) instructions.

The following table summarizes the header support for client access requests.

HTTP Method

Same-Domain calls

Cross-Domain calls

GET

Headers always allowed

Allowed with client HTTP handling only. Must be allowed per client access policy file.

POST

Headers always allowed

Request headers are allowed per client access policy file

Other methods

Headers always allowed

Client HTTP handling only. Must be allowed per client access policy file.

Note Note:

The Mozilla Firefox browser does not currently set the Referer header on HTTP GET requests. As a result, a Silverlight application hosted in Firefox does not support the Referer header being set on any GET requests.

Path Restrictions for Cross-Domain Requests

In addition to requiring a client access policy file, there are restrictions on the characters allowed in the path section of a cross-domain URI that is callable by a Silverlight application, if all paths and sub paths are not allowed. The following illustration shows the path portion of a URI.

Path Portion of a URI

Path of a URI

The following characters are never allowed in a cross-domain request path when paths are restricted by the client access policy file.

  • Consecutive dot characters (..)

  • Dot followed by a forward slash (./)

  • Percent sign (%)

For more information about the format of client access policy files and scenarios they enable, see Network Security Access Restrictions in Silverlight and Making a Service Available Across Domain Boundaries.

Adobe Flash Cross-Domain Policy File

Silverlight supports a subset of the Adobe Flash cross-domain policy file (named crossdomain.xml). Silverlight supports the <allow-access-from> tag with the following attributes.

  • The domain attribute. The only value that is permitted for this attribute is "*", which means that the entire domain is exposed to all callers.

  • The secure attribute. This attribute is relevant only when the target domain is HTTPS. This attribute accepts a value of true or false, which indicates whether HTTP callers are allowed to access resources within this domain.

  • The headers attribute. This attribute lists accepted headers.

The following is an example of an Adobe Flash cross-domain policy file (crossdomain.xml) supported by Silverlight.

<?xml version="1.0"?>
    <!DOCTYPE cross-domain-policy SYSTEM
     "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
    <cross-domain-policy>
       <allow-access-from domain="*"/ headers="SOAPAction" 
         secure="true">
    </cross-domain-policy>

Community Additions

Show:
© 2014 Microsoft