Securing Your Silverlight
In my role as a consultant with Microsoft Services, I have regular discussions
with customers and partners about application security. In this article, I’ll
explore some of the themes that arise in those discussions. In particular, I’ll
focus on the new challenges programmers face when trying to secure Silverlight
applications, and I’ll consider where development teams should focus their
This article touches on many technical concepts that you’ll find covered in more
detail elsewhere (including this magazine). For this reason, I won’t explore
these topics in great technical depth. Instead, the goal of the article is to
“connect the dots” and show how you can exploit these concepts to secure your
When planning security for an application, it’s useful to think of three A’s:
authentication, authorization and audit.
Authentication is the act of confirming that users are who they claim to be. We usually do this with a user name and password.
Authorization is the process of confirming that a user, once authenticated, actually has the appropriate permissions to perform a particular action or access
a particular resource.
Audit is the act of maintaining a record of activity such that actions and
requests made upon a system can’t be denied by the user.
I will focus on the first two, authentication and authorization, in the context of a
Silverlight application. As this is a Rich Internet Application (RIA), the majority
and XML (AJAX) or other RIA approaches. I’ll also discuss how you can prevent
unwanted access to your Silverlight application files.
Silverlight is a cross-browser plug-in that leverages many of the graphical
concepts pioneered by Windows Presentation Foundation (WPF), enabling Web
developers to create rich user experiences far beyond what’s possible with only
Unlike ASP.NET, Silverlight is a client-side technology, so it runs on users’
computers. So Silverlight development arguably has more in common with
Windows Forms or WPF than with ASP.NET. In many ways, this is one of
Silverlight’s greatest advantages, as it removes many of the problems caused
by the stateless nature of Web applications. However, because all the UI code
Services runs on client computers, you can’t trust it anymore.
Unlike Windows Forms, Silverlight operates within the browser sandbox and has
a reduced set of capabilities, so it provides an increased degree of security
(though in Silverlight 4, users can identify certain applications as trusted and
promote the programs’ privileges to allow COM interop). Because of this,
Silverlight can’t connect to a database directly, so you must create a layer of
services that provide access to your data and business logic.
Typically, you host these services on your Web server, just as you would with
your ASP.NET Web forms, for example. Given that Silverlight code runs on the
wrong side of the trust boundary between your servers and the real world (see
Figure 1), the focus of your team’s effort should always be to secure the
Figure 1 Silverlight Runs on the Wrong Side of the Trust Boundary
There’s little point in implementing rigorous security checks within your
Silverlight code itself. After all, it would be easy for an attacker to do away with
the Silverlight application altogether and invoke your services directly,
side-stepping any security measures you implemented. Alternatively, a
malicious person could use a utility like Silverlight Spy or Debugging Tools for
Windows to change the behavior of your application at runtime.
This is an important realization—a service can’t know for sure what application
is invoking it or that the app hasn’t been modified in some way. Therefore your services have to ensure that:
? The caller is properly authenticated
? The caller is authorized to perform the requested action
For those reasons, most of this article focuses on how to secure services in a way that’s compatible with Silverlight. Specifically, I’ll consider two different types of services hosted via ASP.NET in Microsoft IIS. The first type, services created using Windows Communication Foundation (WCF), provides a unified programming model for building services. The second, WCF Data Services (formerly ADO.NET Data Services), builds on WCF to let you rapidly expose data using standard HTTP verbs, an approach known as Representational State Transfer (REST).
Naturally, if security is a concern, it’s always wise to encrypt any communication between clients and servers. The use of HTTPS/SSL encryption is recommended and assumed throughout this article.
Today, the two most common authentication methods Web developers use on the Microsoft platform are Windows authentication and forms authentication. Windows Authentication
Windows authentication leverages the Local Security Authority or Active Directory to validate user credentials. This is a big advantage in many scenarios; it means you can centrally manage users with tools already familiar to systems administrators. Windows authentication can use any scheme supported by IIS including basic, digest, integrated authentication (NTLM/Kerberos) and certificates.
The integrated scheme is the most common choice for use with Windows authentication, because users don’t have to provide their user names and
passwords a second time. Once a user logs on to Windows, the browser can forward credentials in the form of a token or a handshake that confirms the person’s identity. There are some disadvantages to using integrated
authentication, because both the client and server need visibility of the user’s
domain. As a result, it’s best targeted at intranet scenarios. Furthermore, though it works with Microsoft Internet Explorer automatically, other browsers, such as Mozilla Firefox, require additional configuration.
Both basic and digest authentication typically require users to re-enter their user names and passwords when they initiate a session with your Web site. But because both are part of the HTTP specification, they work in most browsers and even when accessed from outside your organization.
Silverlight leverages the browser for communication, so Windows
authentication is easy to implement with any of the IIS authentication methods
just discussed. For a detailed description of how to do so, I recommend reading
the step-by-step guide “How to: Use basicHttpBinding with Windows Authentication and TransportCredentialOnly in WCF from Windows Forms” at
msdn.microsoft.com/library/cc949012. This example actually uses a Windows
Forms test client, but the same approach applies to Silverlight.
Forms authentication is a mechanism that provides simple support for custom
authentication in ASP.NET. As such, it’s specific to HTTP, which means it’s also
easy to use in Silverlight.
The user enters a user name and password combination, which is submitted to
the server for verification. The server checks the credentials against a trusted
data source (often a database of users), and if they’re correct, returns a
FormsAuthentication cookie. The client then presents this cookie with
subsequent requests. The cookie is signed and encrypted, so only the server can
decrypt it—a malicious user can neither decrypt nor tamper with it. Exactly how you invoke forms authentication varies depending on how you
implement your login screen. For example, if you’ve used an ASP.NET Web form
that redirects to your Silverlight application after the user’s credentials have
been validated, you probably have no more authentication work to do. The
cookie already will have been sent to the browser and your Silverlight
application will continue to use the cookie whenever making a request to that
If, however, you want to implement the login screen inside your Silverlight
application, you’ll need to create a service that exposes your authentication
methods and sends the appropriate cookie. Fortunately, ASP.NET already
provides what you need—the authentication service. You just need to enable it
in your application. For detailed guidance, I recommend reading “How to: Use
the ASP.NET Authentication Service to Log In through Silverlight Applications”
Another great feature of ASP.NET authentication is its extensibility. A
membership provider describes the mechanism by which the user name and
password are verified. Fortunately, there are a number of membership
providers available as part of ASP.NET, including one that can use SQL Server
databases and another that uses Active Directory. However, if a provider that
meets your requirement isn’t available, it’s straightforward to create a custom
Once your users are authenticated, it’s important to ensure that only they can
attempt to invoke the services. Both ordinary WCF services and WCF Data Services are represented by a .svc file in ASP.NET applications. In this example, the services are going to be hosted via ASP.NET in IIS, and I’ll demonstrate how
you can use folders to secure access to the services.
Securing .svc files this way is a little confusing because, by default, a request for such a file actually skips most of the ASP.NET pipeline, bypassing the authorization modules. As a result, to be able to rely on many ASP.NET features, you’ll have to enable ASP.NET compatibility mode. In any case, the WCF Data Services mandate that you enable it. A simple switch inside your configuration file achieves the task:
With ASP.NET compatibility enabled, it’s possible to prevent access to unauthenticated users by using the authorization section of a web.config file, also shown in the previous code snippet.
When using forms authentication, the developer must think carefully about which parts of the site need to be accessible, even to unauthenticated users. For example, if all parts are restricted to authenticated users only, how will an unauthenticated user log in?
It’s often easiest to create a folder structure that supports your basic
authorization requirements. In this example, I’ve created a “Secured” folder that contains the MyWcfService.svc and MyWcfDataService.svc files, and I’ve deployed a web.config file. In Figure 2 you can see the folder structure, and the
previous code snippet shows the contents of the web.config file.
Figure 2 Secured Folder Containing the Web.config File
Note that the root of the application must have anonymous access allowed, otherwise users won’t be able to reach the login page.
For sites using Windows authentication, things can be somewhat simpler in this respect, as authentication takes place before the user gets to the resources contained within the application, so there’s no need for a specific login page. Using this approach, it’s actually possible to restrict access to services in a more detailed way, allowing only specific groups of users or roles to access resources. For more information, see “ASP.NET Authorization”
This example implements authorization somewhat, but folder-level
authorization alone is far too coarse-grained to rely on for most scenarios. Authorization in WCF Services
Using the PrincipalPermission attribute is an easy way to demand that an invoker of a Microsoft .NET Framework method be within a specific role. This code sample demonstrates how this might be applied to a ServiceOperation in WCF where the calling user must be part of the “OrderApprovers” role:
[PrincipalPermission(SecurityAction.Demand, Role = "OrderApprovers")] public void ApproveOrder(int orderId)
This is easily implemented in applications that use Windows authentication to leverage the existing facility to create Active Directory groups for organizing users. With applications using forms authentication, it’s possible to leverage another great provider-based feature of ASP.NET: RoleProviders. Again, there
are a number of these available, but if none are suitable, you can implement
Of course, even per-method authorization is rarely enough to meet all your
security needs, and you can always fall back to writing procedural code inside
your services as shown in Figure 3.
Figure 3 Using Procedural Code to Implement Specific Authorization
Public void CancelOrder(int orderId)
// retrieve order using Entity Framework ObjectContext
OrdersEntities entities = new OrdersEntities();
Order orderForProcessing = entities.Orders.Where(o => o.Id ==
if (orderForProcessing.CreatedBy !=
throw new SecurityException(
"Orders can only be canceled by the user who created them");
WCF is a highly extensible platform, and as with all things in WCF, there are
many approaches to implementing authorization in your services. Dominick
Baier and Christian Weyer discussed a number of the possibilities in detail in the
October 2008 issue of MSDN Magazine. The article, “Authorization in
WCF-Based Services” (msdn.microsoft.com/magazine/cc948343), even
ventures into claims-based security, a structured way of organizing the
authorization in your application.
Authorization in WCF Data Services
WCF Data Services, as the name suggests, builds on WCF to provide
REST-based access to a data source—perhaps most often a LINQ-to-SQL or
LINQ-to-Entity Framework data source. In brief, this lets you provide access to
your data using a URL that maps to the entity sets exposed by your data source
(an entity set typically maps to a table in your database). Permissions to these
entity sets can be configured inside the services code-behind file. Figure 4
shows the content of the MyWcfDataService.svc.cs file.
Figure 4 A WCF Data Services Code-Behind File with Configuration of
Entity Set Access Rules
Public class MyWcfDataService : DataService
// This method is called only once to initialize service-wide policies.
Public static void InitializeService(IDataServiceConfiguration config)
config.SetEntitySetAccessRule("Products", EntitySetRights.AllRead |
EntitySetRights.WriteAppend | EntitySetRights.WriteDelete);
Here, I’ve given Read permissions over the Orders entity set and configured the Products entity set to allow full reading, the inserting of new records and the deletion of existing records.
However, because WCF Data Services automatically renders access to your data based on this configuration, you don’t have direct access to the code, so there’s no obvious place to implement any specific authorization logic. WCF Data Services supports interceptors that allow developers to implement logic between the client and the data source. For example, it’s possible to specify a query interceptor that filters the results for a particular entity set. The example in Figure 5 shows two query interceptors added to the MyWcfDataService
Figure 5 Query Interceptors in WCF Data Services
return product => product.CreatedBy == userName;
bool userInPrivateOrdersRole =
return order => !order.Private|| userInPowerUserRole; }
The first is applied to the Products entity set and ensures that users can retrieve
only products created by them. The second ensures that only users in the
PrivateOrders role can read orders flagged Private.
Likewise, it’s possible to specify change interceptors that run before an entity is
inserted, modified or deleted as demonstrated here:
public void OnChangeProducts(Product product, UpdateOperations
if (product.CreatedBy != Thread.CurrentPrincipal.Identity.Name)
throw new DataServiceException(
"Only products created by a user can be deleted by that user");
On initial viewing, the OnChangeProducts change interceptor in this code
sample appears to expose a security vulnerability, because the implementation
relies on data passed from an external source—specifically the “product”
parameter. But when deleting an entity in WCF Data Services, only an entity key
is passed from the client to the server. That means the entity itself, in this case
the Product, has to be fetched again from the database and therefore can be
However, in the case of an update to an existing entity (for example, when the
operations parameter equals UpdateOperations.Change), the product
parameter is the de-serialized entity sent by the client, therefore it can’t be
trusted. The client application may have been modified to specify the CreatedBy
property of this particular product to a malicious user’s own identity, thereby
elevating the usurper’s privileges. That could allow modification of a product by
an individual who shouldn’t be able to do so. To avoid this, I recommend that
you re-fetch the original entity from the trusted data source based on the entity
key alone, as shown in Figure 6.
Figure 6 A Change Interceptor Preventing Unauthorized Insert, Update
and Delete Operations
Public void OnChangeProducts(Product product, UpdateOperations
if (operations == UpdateOperations.Add)
product.CreatedBy = Thread.CurrentPrincipal.Identity.Name;
else if (operations == UpdateOperations.Change)
Product sourceProduct = this.CurrentDataSource.Products.Where(p =>
p.Id == product.Id).First();
if (sourceProduct.CreatedBy !=
throw new DataServiceException(
"Only records created by a user can be modified by that user");
else if (operations == UpdateOperations.Delete &&
product.CreatedBy != Thread.CurrentPrincipal.Identity.Name)
Throw new DataServiceException(
"Only records created by a user can be deleted by that user");
Because this implementation relies so much on the CreatedBy property of the Product entity, it’s critically important that this is enforced in a reliable way from the moment the data is created. Figure 6 also shows how this might be
achieved by overriding any value passed by the client for an Add operation. Note that as the example currently stands, handling operations of type UpdateOperations.Change wouldn’t be an issue. In Figure 4, the service was
configured to allow only AllRead, WriteAppend (insert) and WriteDelete actions to occur on the Products entity sets. Therefore, the ChangeInterceptor would never be invoked for a Change operation, as the service would immediately reject any request to modify a Product entity at this endpoint. To enable updates, the call to SetEntitySetAccessRule in Figure 4 would have to include
WriteMerge, WriteReplace or both.
The Silverlight plug-in can make cross-domain HTTP requests. A cross-domain call is an HTTP request made to a domain other than the one from which the Silverlight application was downloaded. The ability to make such calls has traditionally been viewed as a security vulnerability. It would allow a malicious developer to make requests to another site (for example, your online banking site) and automatically forward any cookies associated with that domain. Potentially, this could give the attacker access to another logged-in session within the same browser process.