Using VS - DevSource
DevSource: Microsoft Developer Resource DevSource Home Sponsored by Microsoft Home Add Ons Architecture Languages Techniques Using VS Forums
Home arrow Using VS arrow Secure ASP.NET AJAX Development (Part 2)
Secure ASP.NET AJAX Development (Part 2)
By DevSource

Rate This Article: Add This Article To:

This is the second in a series of excerpts from the book, Secure ASP.NET AJAX Development.

Reliance on JavaScript

One of the more difficult aspects of implementing AJAX applications is the tremendous

ADVERTISEMENT

amount of JavaScript programming that is usually required. If you refer back to the basic XMLHttpRequest example in Section 1, you see that AJAX in its most basic form is pure JavaScript programming. And even if the developer is pretty skilled with JavaScript programming, AJAX adds an additional layer of complexity by requiring you to have a fairly deep understanding of the DOM in the major browsers and the nuances of each browser's implementation of the XMLHttpRequest object.

The different AJAX client libraries, code generators, and frameworks that we outlined earlier reduce some of this burden of JavaScript complexity by abstracting a lot of the direct DOM and Web service manipulation and browser compatibility. But now you have to learn the JavaScript libraries provided to you by these development toolkits, so there is no getting around the fact that you cannot do AJAX without programming JavaScript. Even with ASP.NET AJAX, the most abstracted of any of these toolkits, you still have to write JavaScript. There is a J in AJAX for a reason, after all.

So where does the insecurity lie in JavaScript? Begin by reflecting on the fact that JavaScript was originally designed to do anything that a user can do, such as click on links or open and close windows. As an attacker, by design I can make a malicious script do everything a user can do, but in your browser. Like most other things we have talked about, JavaScript itself is not an insecure language. It is a very useful and powerful language, but it can do bad things if it is used incorrectly or manipulated by an attacker. Not only do you have to deepen your JavaScript skills to build secure AJAX applications, but also your users have to have JavaScript enabled in their browsers for your AJAX application to work. Some users just simply are not willing to do this, either through fear of script injection or because of corporate acceptable-use policies, but your AJAX application will not work otherwise.

So if JavaScript is not insecure, what is the problem? The security risk in JavaScript is twofold:

  1. JavaScript has complete access to any information accessible in the browser, including HTML forms, page appearance, and content—everything in the DOM and the user's cookies.
  2. Because JavaScript is downloaded and run in the client, it can be modified easily by an attacker.

Combine these risks with the fact that executable JavaScript code can be persisted in Web pages and run automatically in the background at predetermined intervals, all without the user knowing, and you can imagine all of the bad things that are possible with liberal use of JavaScript. Some Web services even send JavaScript functions back to the browser in clear text and the browser executes them without question. In fact, JavaScript on the client is integral to each of the remaining security pitfalls discussed in this section.

The only way to absolutely protect your application and your users from malicious JavaScript is to disable JavaScript in the browser, but this obviously is not practical in an AJAX application. What you need to do instead is to take precautions to ensure that you do not make sensitive resources available to client script and do not implement sensitive functions in vulnerable JavaScript code.

Cross-Site Scripting

Cross-site scripting (see Figure 2-5) is one of the more dangerous security vulnerabilities in Web applications and has become the avenue of choice for attackers in recent years. Cross-site scripting describes a vulnerability whereby an attacker is able to execute malicious script code in a user's browser to gather data from the user. Through this ability to run script on someone else's client browser, the attacker can do a wide variety of bad things, including stealing cookies and hijacking session information and using it to impersonate your user session with the server. Attackers can also use it to deface sites by altering page content and to impersonate a real site to capture login information. Cross-site scripting attacks can also result in key logging where every key you enter into a page is sent off to an attacker's server through innocuous-looking image tags.

The bright side of cross-site scripting is that even though it is extremely dangerous, it is also fairly easy to prevent. Attackers are able to execute script on a client browser through your application by sending the malicious script to your server through an unprotected input or by storing it in your datastore. If your server fails to catch the properly escaped and formatted malicious script and repeats it back to the client browser when rendering the page to the user, the script is executed in the browser with the same trust and access as everything else your server sent to the browser. Because your server has rendered the malicious script back to the client, the client assumes that it is safe and treats it like everything else in the page, allowing it full access to your cookies, DOM, and so on. Your server may not always trust the requests from every client, but your browser always trusts the server.

From this explanation of the mechanics of cross-site scripting, you can see there are two key points where you can block this attack: input validation and output encoding. If you properly filter all of the inputs into your application, including those from your own datastores, no malicious script could possibly get to the server. Furthermore, if validation is bypassed somehow and the server is injected with the malicious script, the server can prevent the script from being sent to the browser in executable form by encoding the output to the browser. The natural instinct for many developers is to then perform blacklist validation to block <SCRIPT> tags and other characters common in JavaScript, but this is an inadequate approach. The input validation discussion in Section 3 outlines how to effectively and safely validate inputs.

The easiest way to determine whether a Web application is vulnerable to cross-site scripting is to try to get the application to execute JavaScript for you somewhere it should not. You do this simply by entering a valid JavaScript expression into a field, often with HTML escape characters to make it flow in the application. The most common application types that are vulnerable to cross-site scripting are search and forum pages where user input is redisplayed on the page. For example, on a search page, if I search for "Texas", the page will often repeat at the top "Search results for: Texas" to give the user context for the search results displayed. The HTML for this would look something like this, oversimplified for brevity:

<html>
<body>
   <p>Search results for: Texas</p>
   Dallas, TX
</body>
</html>

If I want to try to attack the page, instead of entering "Texas" into the search field, I could enter the following expression to see if the page may redisplay my malicious script in the browser, which interprets and executes it:

The server would then send the following HTML to the browser, with my script injected:

<html>
<body>
   <p>Search results for: <SCRIPT>alert("Hello world.")</SCRIPT></p>
</body>
</html>

The browser would interpret the script and execute it as though the server intended for that to happen, which would result in an alert pop-up. You might think that it would be easy to defeat these attacks by simply stripping <SCRIPT> tags out of inputs, but there are hundreds of alternative ways of attempting these attacks. (Note: Test a few of these alternative cross-site scripting attacks on your applications to see how easy it can be to defeat content filtering: http://ha.ckers.org/xss.html) The simplest example of how cross-site scripting is possible is an entry point for an attacker to inject much more clever script code that reads your authentication cookie and sends it off to a remote server so that the hacker can impersonate your online banking session and wire money to himself. Attackers typically initiate these attacks by tricking users into clicking links that contain the malicious script to execute in the browser when you visit the vulnerable site. (Note: For an advanced example of cross-site scripting, see the SPI Dynamics white paper on the topic: www.spidynamics. com/assets/documents/SPIcross-sitescripting.pdf.)

Now that we have covered the basics of cross-site scripting and how dangerous it can be, let's see how AJAX makes cross-site scripting an even more dangerous problem for you. With traditional cross-site scripting, the attacker has to convince the user to somehow click a link or make an explicit request of the server with the malicious script included in the request. With AJAX technologies, attackers that are successful in injecting script into your page can make malicious requests asynchronously. In other words, the scripts can persist in your pages and periodically send interesting things about you and your session off-site to the attacker's server.

Cross-site scripting with AJAX still requires the attacker to compromise your application by injecting malicious script, either by your server repeating back unvalidated input that gets executed by the browser, or through persistence in databases or data files that the application uses to display data. AJAX just makes these scripts stealthier and much more powerful and contagious.

Cross-Site Request Forgery

Cross-site request forgery is a particularly nasty variant of cross-site scripting whereby an attacker can send trusted requests to a Web application on the user's behalf with all of the user's privileges. (Note: For a detailed description of cross-site request forgery, see iSEC Partners' white paper on cross-site reference forgery, which is a different name for the same problem: www.isecpartners.com/files/XSRF_Paper_0.pdf.) Although cross-site scripting is made possible when a user trusts a Web application, cross-site request forgery is made possible when the Web application assumes that requests coming from a user are safe. In the last section, we discussed how an attacker can steal cookie information from a user through cross-site scripting attacks and then use those cookies to impersonate your sessions. This is an involved and tricky process, but cross-site request forgery eliminates the need to find and steal user session cookies by sending malicious requests directly from the user's browser.

If a user is logged in to an application and session state is persisted in some way, most commonly through cookies, the browser will automatically attach the session information to any requests sent back to the Web application with which it has been authenticated. By initiating the requests back to the authenticated application from the browser through malicious code, such as an image tag, the attacker is able to instruct the server to do anything that the user is allowed to do. In an extreme example, if a user is logged in to his online brokerage account and an attacker is able to forge a request, the attacker could ask the server to sell a bunch of stock or to transfer money to some random account. The attacker can also initiate the request by tricking the user into making the request through an encoded or obfuscated link or by clicking on an infected image tag.

As was the case with cross-site scripting, cross-site request forgery is already a problem with many traditional Web applications. AJAX again just makes it stealthier and more persistent and dangerous (see Figure 2-6). With AJAX, the malicious script in the user's browser can make the stock trade or bank transfer asynchronously, with the full authority of the user, so that the user knows that the transaction occurred only after it is too late. Once again, the good news is that this is preventable through some input validation and output encoding to prevent script injection and cross-site scripting, but more sophisticated request authentication is required than with cross-site scripting prevention.

Cross-Domain Requests

One of the newer uses of AJAX technologies is to create applications that aggregate content from multiple sources into a new composite site. These Web sites are known as mashups and typically draw content from Web services or RSS feeds. A common example is to merge mapping providers such as Google Maps or Microsoft Virtual Earth with another service that provides location-based data, such as real estate sales. HousingMaps (http://housingmaps.com) is a simple example of such a site that combines information from Google Maps and craigslist to show houses for rent across the United States. The HousingMaps application is in no way affiliated with craigslist or Google, but it is able to use the public APIs exposed by those companies through Web services to aggregate the content, or mash it up, into an altogether new type of Web application. This creative abstraction of multiple Web sites into a new Web experience is increasingly being called Web 2.0.

To build these mashups, developers usually have to aggregate the content from multiple services on the server side of the application to circumvent some security restrictions built into modern browsers. Browser security restricts calls exclusively to the same domain from whence the current page came, except for linking to external resources such as images, script files, and CSS files. In other words, if you are viewing a page on forums.yoursite.com, the page cannot make requests to photos.yoursite.com much less pull information directly from an untrusted third-party site such as http://maps.google.com. This restriction was intended to protect Web site owners from having their content stolen and redisplayed on someone else's site and to prevent malicious code, such are cross-site scripting attempts, from sending stolen information off-site to an attacker's server. The XMLHttpRequest object central to AJAX honors this restriction, as well.

These cross-domain restrictions make mashups difficult, especially in the AJAX environment where developers want to combine content dynamically on the client without requiring server round trips for every request to a third-party service. Developers are currently forced to push this work off to the server, where they can safely make cross-domain requests through Web service proxies. To enable the actual mashing up of content, AJAX developers are coming up with creative ways around the cross-domain restriction.

A particularly clever method for accomplishing cross-domain requests from the browser involves a combination of dynamic script tags and an emerging lightweight data interchange format called JavaScript Object Notation, or JSON. JSON is a serialized representation of a JavaScript object that can be converted back into an object in the browser. If the object happens to be a JavaScript function, the browser can directly execute the JavaScript code sent as JSON. With this method for making cross-domain requests, JavaScript code in the browser makes a request to the server, which responds with a callback function and JSON formatted to produce valid JavaScript. The browser evaluates the JSON-formatted JavaScript callback, which results in a cross-domain call to a Web service when interpreted in the browser. In order to execute the callback function, the JavaScript dynamically adds a script tag to the page, which results in the execution of the JSON Web service call across domains.

Naturally as the demand grows for cross-domain request support in AJAX toolkits, vendors will begin to honor it. The Dojo script library appears to be the first to move in this direction by supporting cross-domain requests through an IFRAME proxy. ASP.NET AJAX includes an alternative method for accessing external Web services through a feature known as Web service bridges. Bridges are components on the server that interact with the external Web services on behalf of the browser, much like a service proxy. The bridge technology is not committed for full support in ASP.NET AJAX, but it will be available shortly afterward as a feature pack or code sample and later possibly wrapped into the framework.

Because developers are finding ways to make these cross-domain requests, whether supported by their AJAX toolkit of choice or through clever hacks, you need to understand two important security risks of opening up these holes. First, you may be enabling attackers to download malicious scripts from their own servers into your browser and they may be able to send stolen data directly back to their servers. The cross-site scripting attacks outlined earlier typically have to rely on image tags to send information off-site in a fragmented and unreliable manner, but cross-domain request support enables them to make direct requests to their own servers. If you give them a mechanism to make asynchronous service calls across domains, they can send information to their server easily and without user detection. The idea of a JavaScript keystroke logger that sends everything you type to an attacker's Web service is now simple to accomplish and is already a reality.

Second, attackers can abuse your server-side cross-domain service proxies to attack the third-party Web services your application uses. If an attacker can gain access to your service proxy or Web service bridge, he can then impersonate you as he attacks the other server because he will be acting through the proxy or bridge on your server. You can imagine how quickly Google Maps or Microsoft Virtual Earth would cut you off or come after you if it found your server to be attempting hacks against its services.

Web Services

The flexibility and growing use of Web services are partly responsible for fueling the growth in AJAX development. Web services have been around and in use for several years, mostly in corporate environments through service-oriented architectures (SOAs). They have become popular in mainstream consumer Web applications only in recent years with the availability of Web service interfaces from Internet titans such as Google and Amazon, to newer services such as craigslist. For example, several years ago Google made its market-leading search capabilities available through a Web service, enabling any Web developer to quickly integrate this search technology into his applications. This rapid growth in Web services development and availability has made AJAX applications much richer, given the number of options for creating mashups and the relative ease with which developers can create new Web services.

AJAX applications' use of Web services does not introduce any incremental security risk over any other use of Web services, but AJAX certainly encourages you to introduce more public Web services to support your application. By opening more Web services to the public than you might have otherwise, you need to be careful to given plenty of attention to these new avenues of attack to your server.

Command injection attacks such as XML injection and SQL injection are the most common security problems with Web services. With XML injection, an attacker attempts to send malformed XML requests to your Web service to obtain sensitive information. A SQL injection attack on a Web service is no different from one against a Web application. A hacker sends SQL commands to your Web service in an attempt to get your server to execute them against the database. Another common Web service attack is a type of denial-of-service attack known as XML bombing. In this attack, the attacker exploits weaknesses in your XML parser by sending XML documents with recursive references, causing infinite loops in your data parser and potentially slowing or crashing your service. Web services offer the attacker the added benefit of clearly delineating all of its available methods and data types through interface descriptors such as WSDL and ASMX files. In a way, they make it even easier for a hacker to learn about the inner workings of your server-side code than do Web applications because the contract is public to allow other applications to consume the service.

The takeaway for you from this brief introduction of Web services security risks is that AJAX

does not introduce any additional vulnerability into your system by virtue of its Web services consumption. It just encourages you to create more public Web services and in doing so gives you more opportunities to make a mistake in a public interface than you would before AJAX.

Protection from These Pitfalls

The whole realm of Web application security is relevant to you as an AJAX developer, but we assumed in the beginning of this section that you already had a baseline of security in your Web applications before you added any AJAX capabilities to it. In this section, we covered all of the security problems that AJAX makes worse for you, or at least more complicated, but you cannot rest on your laurels and forget about the basics of securing Web applications. AJAX complicates the security profile of your Web application, but it does not make it any harder to secure your application if you follow a few basic secure development principles, which we will outline in Section 3.




Discuss Secure ASP.NET AJAX Development (Part 2)
 
>>> Be the FIRST to comment on this article!
 

 
 
>>> More Using VS Articles          >>> More By DevSource
 



Top Technology Pros One-to-one

All Videos >

Julia explores the Robotics Studio!

Read now >

Messages to Bill Gates!

Read now >

View Now
DevSource RSS FEEDS
XML Want an easy way to keep up with breaking tech news? And the Get DevSource headlines delivered to your desktop with RSS.