JSON Hijacking and How ASP.NET AJAX 1.0 Avoids these Attacks
Recently some reports have been issued by security researchers describing ways hackers can use the JSON wire format used by most popular AJAX frameworks to try and exploit cross domain scripts within browsers. Specifically, these attacks use HTTP GET requests invoked via an HTML <script src=""> include element to circumvent the "same origin policy" enforced by browsers (which limits JavaScript objects like XmlHttpRequest to only calling URLs on the same domain that the page was loaded from), and then look for ways to exploit the JSON payload content.
ASP.NET AJAX 1.0 includes a number of default settings and built-in features that prevent it from being susceptible to these types of JSON hijacking attacks. Below are some details of how these attacks are mitigated:
ASP.NET AJAX Web Methods do not enable HTTP GET requests by default
Script files loaded via an HTML <script src=""> element within a browser can only be retrieved via HTTP GET verb requests.
By default ASP.NET AJAX's web services layer does not allow web methods to be invoked via the HTTP GET verb. For example, assume a developer writes a web service method like below:
public StockQuote[] GetQuotes(string symbol) {
}
ASP.NET will only allow the above GetQuotes method to be called via the HTTP POST verb, and will reject all attempts to invoke the method via an HTTP GET verb.
To make an ASP.NET AJAX web-method callable via HTTP GET-access, a developer must explicitly attribute each method using ASP.NET's ScriptMethod attribute (and set the UseHttpGet property to true):
[ScriptMethod(UseHttpGet=true)]
public StockQuote[] GetQuotes(string symbol) {
}
Although this type of modification is easy to make, it requires a developer to intentionally GET enable a web service. ASP.NET AJAX web services can never be non-deliberately GET enabled, and the ASP.NET AJAX documentation explicitly recommends against GET enabling web-service end points for a number of reasons (risk of url tampering being one of them).
Note: the ASP.NET AJAX "UpdatePanel" control, as well as the other server controls that ship with ASP.NET AJAX 1.0, do not use HTTP GET and instead use HTTP POSTs when doing asynchronous postbacks.
ASP.NET AJAX Content-Type Header Validation
There is a built-in validation layer of protection that ASP.NET enforces for both GET and POST based ASP.NET AJAX web methods, which is that regardless of the HTTP verb being used, ASP.NET always requires that the HTTP Content-Type header is set to the value application/json. It this content type header is not sent, ASP.NET AJAX will reject the request on the server.
Using the stock quote method shown earlier, an HTTP trace of an ASP.NET AJAX GET invocation must look like the following:
Accept: */*
Accept-Language: en-us,fr;q=0.5
Referer: http://xxxxxx/StockService/test.aspx
Content-Type: application/json; charset=utf-8
UA-CPU: x86
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2)
Host: xxxxxx
Proxy-Connection: Keep-Alive
Note that even though the above is a GET request, the client-side ASP.NET AJAX JSON stack still inserts a Content-Type HTTP header that tells the server to consider this an AJAX web service request. The server-side web services stack for ASP.NET AJAX 1.0 always checks for this specific content type, and if it is not found it will reject the request.
If a malicious developer attempted a cross site request forgery attack using HTTP GETs against this web service, they might include a script tag in their page like the following:
However, browsers will not set the Content-Type to application/json when parsing a <script src=""> element and making the request. As a result when ASP.NET receives a request made from a <script /> include, it will not recognize it as a request to an ASP.NET AJAX web service, and it will result in an error from ASP.NET stating that it does not recognize the requested URL. This will prevent JSON Hijacking attempts (even if you have the GET verb enabled for a web method).
Summary
ASP.NET AJAX 1.0 by default only allows the HTTP POST verb to be used when invoking web methods using JSON, which means you can't inadvertently allow browsers to invoke methods via HTTP GET.
ASP.NET AJAX 1.0 requires a Content-Type header to be set to "application/json" for both GET and POST invocations to AJAX web services. JSON requests that do not contain this header will be rejected by an ASP.NET server. This means you cannot invoke an ASP.NET AJAX web method via a <script src=""> include because browsers do not allow append custom content-type headers when requesting a JavaScript file like this.
Hope this helps,
Scott