Silverlight, WCF, Security And Things You Might Not Know

Secure Silverlight/WPF applications that use WCF Services. Includes obfuscation, SSL, encryption, security issues with reflection, WCF configurations, etc...

Even the defense department security protocols are breached on occassion. So, to think that the security policies we've put in place are 100% fool proof is a bit naive. Securing applications is all about determining risk if a breach occurs, lowering that level of risk, and reducing the number of people who are technically knowledgeable enough to pull it off (and not all attackers have the same skillset or background).

The end goal is to make it take more effort to breach your security protocols than it is worth. Of course, this is easier said than done and often requires numerous small steps to achieve. Personally, I like to apply both known best practices, obfuscation, encryption, and a healthy amount of purposeful confusion.

Every application and its data is different which makes writing an article that gives you a complete set of best practices impractical. What I'll do instead is to give you some things to think about and some suggestions as to how you might address them. For now, I'll focus strictly on Silverlight applications that reference your WCF service. A typical Silverlight / WCF architecture looks a little like this:

Silverlight -> SSL -> WCF Service -> Business Logic -> DataBase
Silverlight <- SSL <- WCF Service <- Business Logic <- DataBase

The areas in red represent potential security holes and the areas in green are your last line of defense. Not only is Silverlight a red area but so is the SSL secured network traffic between itself and the WCF service.

WCF Suggestions

1. ClientAccessPolicy.xml

This file helps you control which domains have access to call your WCF service. Here is a very basic example of how you can restrict access to only those applications running under your desired domain. This permits someone running your Silverlight application from both a secure and a non-secure url.

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

2. Secured Socket Layer Certificates (SSL)

Use secure socket layer certificates to protect "most" sets of prying eyes from monitoring unencrypted network traffic. This requires an increased level of expertise, hardware, and software to monitor your data transmissions. Assume that someone knows how to use a networking tool like Fiddler to monitor your Silverlight application's network traffic and thus discover your WCF service url. Also assume they know how to use Fiddler's capability to decrypt SSL encrypted traffic.

Yes, every piece of data you transmit back and forth from your Silverlight application to your WCF service can be decrypted by tools like Fiddler. This refers specifically to data you did not encrypt inside your application(s) and only to data encrypted automatically via the SSL certificate. They would just fire up Fiddler and configure it to decrypt SSL traffic. Then, launch your Silverlight application in their browser. Fiddler would immediately decrypt all traffic to and from your Silverlight application as it transmits/receives data from your WCF service. If you have ever heard of "man in the middle" attacks, this is a good example of a simplistic one.

All of that said, unless the end user is running an unsecured wireless configuration on their laptop, the risk is low that your WCF service would expose something to a hacker that is potentially harmful to another user.

However, you also need to protect your service from exposing information to your user that you only want your Silverlight application to see. Application secrets or proprietary company information that no one should ever see come to mind. The rule of thumb I use when sending secrets over SSL is that if you don't absolutely need to send it, don't.

Here is just one example. If your application retrieves user accounts other than the hacker's own account, they could decrypt SSL encrypted strings and expose passwords belonging to other users. Even if the password itself is encrypted in the database, having the encrypted value is one step closer to a breach. Since the Silverlight application doesn't need to use the passwords of these other users, one option is that we could just clear that property value in the WCF service. You will need to evaluate the risk of sending each and every class property over SSL and make the appropriate adjustments.

3. WCF Service Meta Data

If your service is only going to be used by your applications, you should not publicly expose the meta data. It is the meta data that enables someone to most easily determine what your service, operation, message, and data contracts look like. Many client applications dynamically assign their web service urls at runtime. However, your Silverlight application does not need to see the WCF service meta data in order to create the endpoint binding to a different production web service url at runtime.

Why not? When you created a service reference to your WCF service running on localhost, those classes created by Visual Studio .NET that act as your service reference can be pointed to a different service url at runtime. The classes are tied directly to ServiceContract namespaces but not to the actual web service url. As long as the service contracts that exist in your development environment are the same as those you've deployed to production, it will work properly.

To hide the meta data, you should remove the highlighted line below from your web.config file when you deploy this to production:

<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
<services>
<service behaviorConfiguration="Your Service Behavior Name" name="Your Service Name">
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />
</service>
</services>

Also, you'll need to change the highlighted properties from true to false:

<behaviors>
<serviceBehaviors>
<behavior name="Your Service Behavior Name">
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="false"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>

4. Alter your service contract namespaces

[ServiceContract(Namespace = "https://www.google.com")]
public interface IServiceReference1

Various ServiceContract attributes will show up in the service references created by Visual Studio .NET. Many of these references are not obfuscated or string encrypted (obfuscation discussed in the Silverlight suggestions section) by obfuscation tools. They are clearly visible using Reflector (also discussed below). So, make sure people can see only what you want them to see. One last thing, if you change some of these attributes, you will need to update the service reference in your Silverlight application.

5. Customized Access Tokens

I like to require one or more custom access tokens be passed in to each WCF service operation. The WCF operation would be responsible for validating the token prior to operation execution.

6. Assume You Will Fail To Secure Your WCF Service

Someone with the right know-how and motivation may get by steps 1 through 4. You should carefully review each WCF operation and what it does in order to determine the risk if that operation is called inappropriately. Keep in mind, your operation contracts can be called in any order and at anytime. You can't trust that a series of steps has taken place prior to the execution of the contract. Also, critical operations should not trust that the values of their input parameters have come from their own client application or the user designated as having sent them.

Add extra parameters in these critical operation contracts requiring the user to authenticate, validate permissions, retrieve existing records, and compare ownership/access rights prior to allowing the query, data change, or data delete to occur. Not every operation contract requires this level of complexity. Operation contracts that return look up tables probably would not qualify. An operation contract that enables user passwords to be changed probably would.


Silverlight Suggestions


1. Assembly Obfuscation and String Encryption

As I'm sure you know, tools like Reflector are out there that will let anyone disassemble your .NET assemblies into readable and usable source code. Obfuscation and string encryption of your assemblies makes this much, much more difficult.

There are numerous third party .NET obfuscation and encryption tools. The free versions typically aren't secure enough for corporate applications. Most of these tools are used on a single build machine. It is important to note that many obfuscation tools do not come preconfigured to obfuscate Silverlight assemblies. You will most likely need to include the paths to your version of Silverlight in their user defined assembly path section.

After you have compiled your application into a .xap file (compressed file containing your compiled Silverlight assemblies) via Visual Studio .NET, copy your .xap file over to your build machine, obfuscate, string encrypt, and then zip up the obfuscated assemblies into your deployable .xap file. You could use WinZip, 7Zip, or just about any other compression tool to recreate your .xap file.

Most current obfuscation software will cause your Silverlight application to choke at runtime if you attempt to obfuscate an assembly with XAML in it. They just don't handle this well. So, keep all mission critical C# code that you don't want people to see (which means every single line you can possibly obfuscate :) in separate assemblies. The Model/View/ViewModel pattern takes care of this for us if you put the Model and ViewModel in different assemblies from the View. Follow the pattern and you'll end up with XAML code behind classes that you could care less whether someone can view.

2. Runtime Reflection

You may be tempted to hard code secrets into your assemblies versus exposing even an encrypted value in a config file. Should you do this, remember that these secrets can be extracted at runtime using reflection. As an example, someone could take your .xap file from their browser cache, decompress it, and then include some of your assemblies in their own Silverlight application. Fire up the debugger in Visual Studio .NET and start stepping through code looking at method return values and property values.

Paste the following code in a .NET console application and you'll see what I'm referring to. Notice how it
was even able to extract values of private class level variables. However, Reflection cannot interrogate local variables declared inside methods and event handlers.

using System;
using System.Diagnostics;
using System.Reflection;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var blog = new Blog();
var fieldInfos = blog.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance);

foreach (FieldInfo fieldInfo in fieldInfos)
{
Debug.WriteLine(fieldInfo.Name +" "+ fieldInfo.GetValue(blog));
}

}
}

class Blog
{
private string _test = "this is a reflection test.";
public string MyProperty { get; set; }
}
}

Another trick centers around hard coded strings that you may think are hidden by using the obfuscation and string encryption process. You are partially correct. Tools like Reflector won't be able to expose the string encrypted value but runtime Reflection certainly could.

If you really need to store critical secret hard coded strings, ask yourself if the Silverlight application needs to decrypt them or not. If not, encrypt the string via some other tool (maybe a whipped up console app of yours) and paste the encrypted string in your code instead and remove all references to the encryption key from your application (and never transmit it to or from your Silverlight application). Again, it is just one more level complexity for someone to have to work through.

3. Silverlight 3.0 Does Not Support Code Access Security

Without getting into too much detail, I often place very low level hidden environment oriented checks in various assemblies preventing their misuse outside my applications. Let your imagination run wild here.

4. Wrap Business Logic Classes Around WCF Service Clients

Try to set as much of your code that directly interacts with your WCF service reference to private or internal. Only expose your wrapper methods and event handlers to the public interface. This makes misuse of your own assemblies to call your WCF service inapproriately that much harder to do.

5. Purposeful Confusion

I have also been known to purposely provide inaccurate error messages, config settings, urls, and a wide variety of other pieces of information to make diagnosing failed hack attempts that much more difficult. Don't tell them anymore than is absolutely necessary and attempt to track failed actions. Just because they failed doesn't mean they didn't get close. Clues as to what types of attempts are being made can help you refine your security plan.

6. Lock Down Source Control Of Key Assemblies

This is pretty much standard practice. If you have things in your Silverlight or WCF code you don't want the outside world to see, you should reduce the number of your own internal software developers that have access to it. Nothing like a knowledgable disgruntled employee attempting to create issues for you.

Summary

As I mentioned above, nothing is 100% fool proof but I think these suggestions used in conjunction with one another can go a long way toward securing your applications or at the very least making them a pain to disect. Of course, there are other things I do but would prefer not to make them public.

There are a lot of creative and knowledgable people out there. If you are one of them and would like to contribute additional suggestions, please add your comments at the bottom of this article.

By Robbe Morris   Popularity  (13020 Views)
Picture
Biography - Robbe Morris
Robbe has been a Microsoft MVP in C# since 2004. He is also the co-founder of NullSkull.com which provides .NET articles, book reviews, software reviews, and software download and purchase advice.  Robbe also loves to scuba dive and go deep sea fishing in the Florida Keys or off the coast of Daytona Beach. Microsoft MVP