I've just finished reading an article by one of my favourite WPF bloggers, Josh Smith
, entitled Zen and the art of WPF
. In the article he discusses a security vulnerability exposed if you were to merely disable or hide a button in WPF. The example has a Delete button which should only be used by an 'UberUser' and is therefore hidden for 'LoserUsers'. He then uses the awesome Snoop
tool to make the button visible again such that it could be clicked, even by a lowly LoserUser!
The article reminded me of a discussion I've had with several customers and during a number of Architectural Roundtables - the core theme of the discussion being this: UI security is not security, it's just eye candy
In his article Josh prevents the Snoop hack by implementing an RoutedCammand's CanExecute function like so:
void Delete_CanExecute(object sender, CanExecuteRouteEventArgs e)
_userRights == UserRights.UberUser;
However, this fix is only as good (or bad depending on your viewpoint) as the tools the malicous user chooses. There's very little that can't be achieved with the Visual Studio 2005 debugger and/or Debugging Tools for Windows
I could set a break on the Delete_CanExecute method and set e.CanExecute to true. Hacked.
I could even dig out a reference to the Window1 object and call DeleteExecuted() directly. Hacked.
In any client-server/n-tier architecture the client is always at risk. It might be a browser, a smart-client written in WinForms/WPF or even a Silverlight application. The upshot is when it comes to security the server can never trust the client and three A's of security should always be in place at the server level:
- Authentication - the client must authenticate with the server
- Authorization - the server must authorise each operation (for example, can this user delete accounts?)
- Audit - we should record the operation so we know who deleted the account and when
If these aren't in place then you can rest assured that any malicious user worth his salt won't waste his time tinkering with your UI, chances are they'll go straight for the server.
Don't get me wrong, I'm not against hiding/disabling features in the UI based on the user's privileges. But this isn't
security - it's just visual nicety to make the application more usable.
Therefore I wouldn't worry too much about what a user could do to my UI using snoop or ManagedSpy/Spy++
- it'll serve them right when the app crashes thanks to the AccessDeniedException thrown by the server ;)
25 Feb 2008
» Next Post:
Grabbing the Visual Tree for an item displayed by an ItemsControl
« Previous Post:
Different DataTemplates for different data
Comments are closed for this post.
25 Feb 2008
Nice post. I agree that it's more important to have the server validate user credentials before performing any action. But I don't see that as an excuse to not keep security in mind on the client.
Here is a more realistic scenario that proves my point. Suppose you are working on a very large application, and you are on the client app team. There are various teams working on the back-end. Some of the back-end systems are legacy, some are new, some work well, some don't yet. In a situation like that you don't have any control over how the back-end works, or any knowledge of what it is doing. At that point, you should make absolutely no assumptions about how secure the server is. At that point, the client app security is just as important as the server security.
Client app security can be more than just eye-candy.
25 Feb 2008
I guess my point is that the change you make doesn't make your application any more secure. It only avoids the hack because the malicious user in your post chose to use Snoop instead of some other tool.
However, there is a different benefit to the change you make. If you use commands in the way you prescribe and properly implement the CanExecute method as you describe then, when a developer comes along and uses the DeletedCommand on some other control (a context menu for instance), the enabling/disabling will work right off the bat for different users.