Not too long ago, I received a letter from a friend of mine (well, I do expect love letters, but my expectations remain expectations). By the way, in that letter of his, he wrote about how his Facebook's password got hacked, the person who did this, abused his girlfriend a lot, she therefore broke up with him and now that poor fellow is single. Thus it is proved again, why security is so important, well it can actually make you single.
Between server to client, data traverses through channels, these channels might be secure, or might be so dramatically insecure that your data can literally be read if not encrypted. Silverlight is a client side technology, that means you need to send data, a lot of it in fact, from server to client. While doing this, data will have to travel through a rather not so secure route, if the data contains sensitive information like passwords, hash codes etc., it might cause critical damage to the application of yours. WCF RIA services, a technology based on WCF’s architecture provide solution. We’ll shortly see how can this be implemented. But for now, let’s take a quick look on how WCF RIA can be linked with silverlight. I’ll be tutorializing the overall process in a series that I’ve already planned, but right now I’ll be showing a glimpse of how can it actually be done, in short.
It all begins with creation of a database. The database with single table. As I have mentioned already how to create database in my previous post, Custom authentication in silverlight, so instead of going in detail of it I am just going to start with the real stuff, creating application. Here is how my table ImportantPerson in SecureService database looks like.
Create a new silverlight application with the name SecureService.
Check Enable WCF RIA service in the popup that appears next. Now come the same old, Mainpage.xaml. Let’s not do anything in this page as of now, instead lets create an Entity data model first. Entity data model is the model of the database that act as a mid tier between the database and service. You might use another methods that are readily available to communicate with your database from services, but the Entity data model is one that is most suitable candidate for the task. So add an entity data model for the database we have just created. Get to know how to do that in Creating Entity data model from database.
Right click on the web project, go to add->new item and select the domain service class and name it as, SecureDomainService.
Once you have created the WCF RIA service basing it on the entity data model of yours, silverlight should have created four functions for you for four basic operations, read, update, delete and create. From the perspective of security, you need not to have all the four functions, if you are not intended to delete or update or edit the entry. Also when you are fetching the data, it’s a good and secure practice to filter the data onto the server itself that the client demanded, and then send that filtered data to client, rather than send all the data to client and filter it onto client itself. Though the later process is very fast when the case of filtering is their, but it will take hell lot of time initially when the data is queried for.
For me, I have the following function:
1: public IQueryable<ImportantPerson> GetImportantPersons()
2: {
3: return this.ObjectContext.ImportantPersons;
4: }
Above function was intended to return all the data in the ImportantPerson table to the client. Well let’s see how can this be a threat. I have used a data grid in my main page, bind it with a collection, and when I get data return after firing the above query, I fill the collection with the data returned. Here’s how my overall code looks like.
1: public partial class MainPage : UserControl
2: {
3: private ObservableCollection<ImportantPerson> _personCollection
4: = new ObservableCollection<ImportantPerson>();
5: public ObservableCollection<ImportantPerson> PersonCollection
6: {
7: get { return _personCollection; }
8: set { _personCollection = value; }
9: }
10:
11: readonly SecureDomainContext _context = new SecureDomainContext();
12:
13: public MainPage()
14: {
15: InitializeComponent();
16: var myLoad = _context.Load<ImportantPerson>(_context.GetImportantPersonsQuery());
17: myLoad.Completed += myLoad_Completed;
18: }
19:
20: void myLoad_Completed(object sender, EventArgs e)
21: {
22: PersonCollection.Clear();
23: foreach (var item in _context.ImportantPersons)
24: {
25: PersonCollection.Add(item);
26: }
27: }
28: }
1: <UserControl
2: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4: xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
5: xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
6: xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
7: x:Class="SecureService.MainPage"
8: mc:Ignorable="d"
9: x:Name="MyGrid"
10: d:DesignHeight="300" d:DesignWidth="400">
11:
12: <Grid x:Name="LayoutRoot" Background="White">
13: <sdk:DataGrid ItemsSource="{Binding PersonCollection, ElementName=MyGrid}"/>
14: </Grid>
15:
16: </UserControl>
Now, in short what I am doing, is sending all the data from the server to client. Suppose, the data is classified, as it contains the list of Important officials. (well why suppose? Data has name of my girl too, so it is classified already by default). Server send the data to client via http request it gets from client. Many traffic analyzer tools are available in the market that can easily detect the flow of traffic over the connection, one of them is fiddler. When I analyzed the server’s http response from it, here’s what I found.
I can see the data, I can see the names of the persons literally, I can see everything. So the question is why to send all the data to client when only you need to show a bit of it? If I want to see my name only, then why would I send name of my gf with it? This will do nothing, except challenging the security, in this case the security of my relationship.
In order to avoid that, I have created following query in the server itself.
1: //Protecting my relationship
2: public IQueryable<ImportantPerson> GetMyNameOnly()
3: {
4: return this.ObjectContext.ImportantPersons.Where(x => x.Name == "Neelesh");
5: }
Above function is a Saviour. It protected a lot of me. Changing the Query in line #16 to GetMyNameOnlyQuery() does all the job for me. Here’s what fiddler now have.
Just as silverlight is a client of our SecureDomainService, fiddler can also act as one of the client. Though fiddler is not authenticated to use our service but since our queries did not require any client authentication, any client can use them not just silverlight. For instance, though I have made silverlight to force use my new query, still the original query can be used by other client. That is to say, I can, through fiddler, fire that query and get all the data.
Authentication Required
In order to prevent unauthenticated access, we need queries to only be accessible for authenticated user or client. In WCF RIA, this is however, very easy. you just have to use [RequiredAuthentication] attribute above the queries. This is how it can be done.
1: //Protecting my relationship
2: [RequiresAuthentication]
3: public IQueryable<ImportantPerson> GetMyNameOnly()
4: {
5: return this.ObjectContext.ImportantPersons.Where(x => x.Name == "Neelesh");
6: }
After adding the [RequiredAuthentication] attribute, you also won’t be able to use that query unless you authenticate yourself. I had already showed, exactly how to do that, in one of my previous post Custom authentication in silverlight.
That will solve our unauthorized access problem.
In the nutshell, here’s the checklist for a secure WCF RIA application.
- Expose only those entities that are needed by the client.
- Create queries that provide only the data needed for specific scenarios in the application.
- Filter data to provide only the data normally required for the application.
- Minimize the number of operations for each exposed entity. For example, if an application only needs to add or modify entries, create queries for, insert, and update operations, but not delete operations.
- Use [RequiredAuthentication] attribute in almost all the queries.
- Use https protocols instead of http as https is rather a secure one.
- Keep the number of endpoints to as minimum as possible. We will be discussing about this, in one of my next few post.
This is how you can go secure with WCF RIA services. 100% security is not guaranteed, though.
I sent some Twitter comments, but try this out. In your original example, in MainPage, change line 16 to the following: var myLoad = _context.Load(_context.GetImportantPersonsQuery().Where(x => x.Name == "Neelesh"));
ReplyDeleteTake a look at what you see in Fiddler then.