UPDATE: I got a couple of things wrong in this post, not the least of which is the tone. Sorry to Joe, Billy, and Caleb for offending them. I'm happy that the webcasts are happening and that so many people are learning things from them, and it sounds like future webcasts will address some of the things I felt were missing. Look for the boldface updates below for corrections, and the comments for an interesting discussion.
Joe Stagner from Microsoft has been doing some presentations on security with ASP.NET AJAX along with Billy Hoffmand and Caleb Sima of SPI Dynamics. Go to Joe's blog to get links to the webcasts.
I'm watching the latest now: How Hackers Reverse Engineer and Exploit an ASP.NET AJAX Application, and I'm pretty disappointed. Maybe I have too strict a definition of security.
Security non-issues
The webcast covers the JavaScript proxies that ASP.NET AJAX generates for you, claiming that exposing metadata about the functions and parameters this way is a problem. If your application is vulnerable when an attacker can see the names of the functions and parameters in your web services, then it was already vulnerable. Obscurity is not security.
The example they show is a web service called GetAdminUsers. Then they call that method and get the admin users. If that data is meant to be only accessible by certain users, then the web service should be protected by some kind of authentication (typically forms auth). It's not, so you can see the data. This has nothing to do with AJAX. If it was AdminUserList.aspx and you forgot to protect it via authentication, that would also be a security risk. I think maybe this is another obscurity point... they're saying that without the JavaScript proxy, you might not know that this vulnerability exists. It's a bit like having a receptionist who cheerfully gives out the corporate bank accounts to anyone who calls, but the phone number is unlisted.
They talk a lot about "Direct API Access"... I think this is a misleading term. Security happens at trust boundaries. Validate data at the trust boundary. People have access at whatever interface you gave them, and the interface between the client (user) and the server (your application) is a trust boundary. It doesn't matter whether the mechanics are a page submission or a request via XMLHttpRequest; you need to validate at the trust boundary. To be clear here, I like the discussion and reminder, but I think the webcast missed an opportunity to explain exactly why you need to validate around trust boundaries and how you can determine where those are.
They claim that many developers will put references to their web services in their master page, instead of just on the pages where they need those references. This is described as a "big problem." It's not. It's a mild performance issue: don't include unnecessary code, since it increases load time and memory consumption. They say that things which should only be internal to logged on users will be exposed to non-logged-on users, but that's not true. If the web service is authenticated, then it's authenticated. It doesn't matter whether you tell unauthenticated users about it; they can't call it. This is a complete non-issue as related to security.
The webcast also mentions obfuscated JavaScript and shows a tool to unobfuscate it. I don't think there's much to say here. Obfuscation is not security.
What should have been in there
Just to prove there's more interesting/useful stuff to talk about, I'm going to braindump some security details I've been thinking about lately. Of course, there are still a few webcasts to come, so maybe Joe and the SPI Dynamics guys have plans to talk about these kinds of attacks in the coming weeks.
Cross-Site Request Forgery
UPDATE: Billy tells me this will indeed be covered in an upcoming webcast, so keep watching to learn more about this!
Cross-site request forgery (CSRF) has always been an issue with web applications. The idea is that you're logged in to some web application, and while you're logged in, you visit another (malicious) web page. This malicious page submits a form in the background back to the web application you're logged in on. Because cookies get sent based on the destination of an HTTP request, the malicious page's request uses your credentials, and the bad guys are able to take action on your behalf. (Maybe they post item=helicopter&quantity=35 to BuyNow.aspx. Helicopters are expensive.)
ASP.NET protects you against such forged form posts by using event validation. Briefly, event validation helps to be confident that the form that was just submitted was one actually presented by the server, and not one that was just invented by the malicious page. This is accomplished via hidden fields in the form, a somewhat common method of doing this.
But what about ASP.NET AJAX? When using the UpdatePanel, that same event validation works, but when using web services, there's no such validation. All you get is a method call with some parameters, with no idea where it came from. If you're using forms authentication, then, how can you be sure you're not seeing a forged request? The answer is that any async requests from the browser have to obey the same-origin policy. This is unlike form posts, which can submit to anywhere. That means that a malicious page can submit a request on your behalf, but only if it's hosted on the same domain as the web service.
It gets even more interesting if you dig deeper. ASP.NET AJAX web service calls look like an HTTP POST, just like a form post... uh-oh. Of course, the content that's POSTed is in JSON format, which looks like {"foo":"bar"} instead of foo=bar in a form submit, but if the web service takes no parameters, then both a form post and a web service post have the same content: a null body. Fortunately there's one more thing to distinguish the two. The content-type HTTP header is set to application/json when calling an ASP.NET AJAX web service, and a form post can't fake that. (It will show a content-type of application/x-www-form-urlencoded or multipart/form-data.)
In summary, we're protected from CSRF in ASP.NET AJAX web service calls because:
- The POST request must have content-type: application/json.
- Form posts can't fake that... it has to come from an XMLHttpRequest submission.
- XMLHttpRequest is subject to the same-origin browser policy, and only your trusted script is running on your domain.
If you want to make sure your ASP.NET AJAX application is secure, you just need to make sure those three assertions remain true. Here are some ways you might break those:
- You could enable POSTing to your web service by adding
<add name="HttpPost"/> to your web.config inside the <webServices><protocols> section. Now cross-domain form submissions will be accepted by your web service, and your security is broken by CSRF. (Note that this is no longer an AJAX call, just a regular form submit.)
- Even worse, you could enable GET via
<add name="HttpGet"/>, which means something as simple as a script tag on the page or a malicious link with the right href could take action on behalf of the user. Remember that GET requests should always be idempotent (never take action), but also remember that they should never reveal sensitive data. (Google learned this the hard way recently.)
- You could allow third-party code to run on your domain. This means an attacker no longer needs to forge a request... the request is actually coming from your domain. This is simply cross-site scripting (XSS), and there's a lot of info out there already about the many dangers. ASP.NET AJAX helps a little by doing some verification by default that data submitted via a form doesn't include code. When in doubt, whitelist instead of blacklist. (Only allow plaintext, for example, if you're running a forum or wiki.) Samy, the MySpace worm exploited a subtle XSS bug that slipped through blacklist-style validation.
Client-side (so-called) "validation"
UPDATE: Cool, they actually did a good job of explaining this point in the first webcast in the series.
One mistake I hear about frequently is doing validation on the client instead of the server. Remember this always: validation happens on the server. Whatever you're doing on the client (perhaps using the cool MaskedEdit control from the AJAX Control Toolkit), from a security perspective, you have to assume it's not happening at all. A malicious user can bypass that "validation" in a number of really easy ways. Consider it simply helpful UI for the user (and then it's a best practice). Just don't confuse it with security.
Leaking secrets
UPDATE: I didn't watch the first webcast before posting this, but it sounds like this topic (including this specific exploit) was covered in that one.
A different but sometimes related mistake is leaking secrets to the client. Since many new AJAX developers are used to having all their code securely running on the server, they're not used to thinking about which data and logic it's okay to push down to the client. For example, there was an exploit found recently in the MacWorld Expo registration code, where MD5 password hashes were being included on the page. They were still validating on the server, but those hashes were enough to allow an attacker to perform a dictionary attack. This isn't a new security issue, but it's something that pure server-side developers could basically ignore. (The same logic all on the server would have been okay, since the MD5 hashes would remain secret on the server.)
Hope
I think Joe, Billy, and Caleb all know more about this. I heard about the MacWorld Expo bug from SPI Dynamics, in fact, and Billy was quoted in an article about the exploit. Maybe in future webcasts, they'll talk in more depth about the technology of ASP.NET AJAX and how to evaluate your own applications from a security perspective.
Also, Joe mentioned towards the end of the webcast that he has planned a number of videos covering ASP.NET AJAX best practices, including some security tips. Viewing security from that perspective -- as something you build deeply into your application based on patterns and solid design -- is the right approach. I hope to see some high quality suggestions from Joe as part of those videos.