Once upon a time, there was a WPF application that had two types of users:
The UI had two buttons. One button allowed anyone to view an account. The other button, though, was only for certain privileged people to click, because it deleted an account.
When the program was first released, a careless developer introduced a subtle bug in the logic which determines if an account can be deleted.
For 99% of the non-privileged users, it never dawned on them that it was possible to delete an account when they ran the program.
One of the users had a grudge against the world, and also some knowledge of a little tool known as Snoop. He was determined to bring down The Man one account at a time.
When this malicious user ran the app, he snooped around until he found the hidden Delete Account button.
He found that button’s Visibility property and set it to ‘Visible’.
Since the careless developer did not expect that button to ever be visible when the user is not allowed to see it, the button was not disabled and could be clicked.
Tempting fate, the jaded user clicked the button.
After much fire and brimstone fell from Corporate Skies, the once careless developer learned a valuable lesson. He understood that WPF element trees can be viewed and modified while the application is running. He sharpened his code-sword and prepared for battle.
In one swift movement, he defeated his foe.
After the new version of the application was deployed, the malicious user once again attempted his devious maneuver. However, this time, he found that after unearthing the Delete Account button in Snoop, the button was disabled.
He could not click it. The button’s IsEnabled property could not even be set to true, since the Delete command’s CanExecute handler was forcing the button to be disabled. He could not use the application to continue his rampage against The Man. It broke his heart, and he cried.
Download the application’s source code here (rename the file extension from .DOC to .ZIP).
And the Oscar for best creative dramatization of a geeky technical issue goes to…
Love the images and story
Thx, great article. And because this is funny, a lot of people will take a note of that.
Uh oh. Next time, use AzMan to take care of your security stuff.
You are insane!
After tutoring me for 2 hours on the phone, a nice NY City Dinner, then post the Bomb Blog entry of the year!
Rock On, Rock Star!!!
Brilliant Post….. I love how you wrote it!!!
*L* Loved that
Nice and humorous post.
However, shouldn’t there be a way to prevent Snoop or similar software from changing the UI elements of a running application?
Thanks everybody! I had fun making this post. 😀
Jason: I am not aware of any way to prevent Snoop from inspecting an app’s element tree.
Pwned by teh_sm1th.
By the way, wouldn’t it make sense to do a sanity check in Delete_Executed? Couldn’t there be a way for someone to invoke Delete_Executed from elsewhere, maybe after a careless update by a future developer?
Absolutely. That’s a good point!
It’s important to note that in theory, an application like this would talk to some back-end which does the actual deleting. In this case, no amount of client security will protect things – the server has to be the one doing the authentication and authorization.
It’s like in the web model: Any validation done on the client end is worth zero in terms of security (it may have worth in terms of responsiveness, though!)
In an ideal sense, you’re totally right. I agree.
But as you alluded to, it is beneficial to have secure code at every point in a system. If I release a client app that allows a malevolent user to use a back-door hack to delete an account, I’m part of the problem. It’s not safe or acceptable to assume that other parts of a system do what they should. After a security violation occurs, pointing a finger at the back-end team is not going to help. The client app should not have allowed the security breach either.
[…] for the ToolBar controls in my WPF application. In fact, Josh has recently posted, Zen and the Art of WPF that covers using RoutedCommands. I highly recommand reading this […]
I’m kind of with Avi on this: http://www.thejoyofcode.com/Defense_in_depth_UI_Security_is_never_enough.aspx
Whilst there’s no harm at all in what you’re suggesting here, my concern would be to spend time shoring up the server security before worrying about the client.
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.
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.
Very interesting. You’re right, fixing the canexecute logic to check user rights isn’t going to help much if the user knows how to directly call a method in the app at runtime. However, I’d think that a user who is that tech savvy would probably also know how to get a hold of an Uber User’s username and password, so they could just directly call the back-end stored procs and be done with it.
Can someone send me a copy of the snoop utility? The author’s website blois.us is down and I am desperately trying to work through some WPF problems!
I wasn’t aware it’s that easy to spoof a WPF app. Awesome post!
btw. I will be at MIX next week, maybe there’s a chance to hook up?
Thanks for the feedback!
I won’t be at MIX. 😦
Funny … and a good lesson I will file away.
BTW, I recently downloaded and used the NY Times Reader SmartClient. Very cool … reminds me a little of the iPhone the way the pages swoosh away. Good job.
Great post Josh. It’s interesting to see people picking up on the spoofing angle. Speaking as somebody who’s completely anal about pushing security, I’m pleased to see that people are aware of the issues, but there does seem to be a bit of a misunderstanding creeping in about the difference between authorisation and authentication.
(Hey – it’s 3AM here in the UK, so I may be misunderstanding peoples quotes, but I’m just saying).
Anyway – great post as always.
Ok that has to be one of the best tutorials I’ve ever read. You inspire me to make my post’s more entertaining. Great work!
re: rei’s comment about doing the check in Delete_Executed. You could use a tool like Hawkeye to execute the Delete_Executed directly. I have yet to try Hawkeye on a WPF app, but I assume it’ll “just-work”