23/04/2012

Defending against XSS with .NET

Intro 

This is an older post from my previous blog that now does not exist. 

Use the HttpOnly Cookie Option

Internet Explorer 6 Service Pack 1 and later supports the HttpOnly cookie attribute, which prevents client-side scripts from accessing a cookie using the DOM object document.cookie. If someone uses the that particular DOM object the script will return an empty string. The cookie is still sent to the server whenever the user browses to a Web site in the current domain. Now if you use .NET to set the HttpOnly attribute to true, what practically happens is that the Http header response field Set-Cookie adds one more attribute (except from the ones that is already supposed to have) at the of the line called HttpOnly. It looks something like that:

Set-Cookie: USER=123; expires=Wednesday, 09-Nov-99 23:12:40 GMT; HttpOnly


Now if the Web browser is IE 6 with sp1 and above it wont allow JavaScript DOM object to access the cookie, but if any other browser is used then it does not provide any protection. The thing is that the Set-Cookie is actually used when the web server decides for the first time to log your activity as a web user, meaning for example the after a successful authentication your cookie is going to be used probably as a security token. The following picture shows how someone can use social engineering to make you execute malicious JavaScript and steal your cookie [5].


Picture : HttpOnly option in action [1].

Note: Web browsers that do not support the HttpOnly cookie attribute either ignore the cookie or ignore the attribute, which means that it is still subject to cross-site scripting attacks [5].

Now if the Web browser is IE 6 with sp1 and above it wont allow JavaScript DOM object to access the cookie, but if any other browser is used then it does not provide any protection. The thing is that the Set-Cookie is actually used when the web server decides for the first time to log your activity as a web user, meaning for example the after a successful authentication your cookie is going to be used probably as a security token. The following picture shows how someone can use social engineering to make you execute malicious JavaScript and steal your cookie [5].

It is important for the developer to understant that this property is already set by default for Authentication and Sessions cookies in ASP.NET 2.0 but not for manually issued cookies.  Therefore, you should consider enabling this option for your manually issued cookies as well.  This option can be enabled in web.config by modifying the httpCookies element as in the example below [4]: 

<httpCookies httpOnlyCookies=“true“ /> 

The System.Net.Cookie class

The System.Net.Cookie class in Microsoft .NET Framework version 2.0 supports the HttpOnly property. The HttpOnly property is always set to true when someone is using the Form authentication. Earlier versions of the .NET Framework (versions 1.0 and 1.1) require that you add code to the  Application_EndRequest event handler in your application Global.asax file to explicitly set the HttpOnly attribute. The code that is actually enabling you to use HttpOnly cookie is:

Visual Basic (Usage):

Dim instance As Cookie Dim value As Boolean value = instance.HttpOnly instance.HttpOnly = value 

Code Example: HttpOnly option set using code[3].

In ASP.NET 1.1 the System.Net.Cookie class does not support the HttpOnly property. Therefore, to add an HttpOnly attribute to the cookie you must add the following code to your application’s Application_EndRequest event handler in Global.asax [4]:

protected void Application_EndRequest(Object sender, EventArgs e)
{
string authCookie = FormsAuthentication.FormsCookieName;

      foreach (string sCookie in Response.Cookies)
      {
            if (sCookie.Equals(authCookie))
            {
                  Response.Cookies[sCookie].Path += “;HttpOnly”;
            }
      }
}

Code Example: HttpOnly option set using web.config [4]. 

Do Not Rely only in the HttpOnly flag for XSS issues

The HttpOnly protection mechanism is useful only in case where the attacker is not skillful enough to undertake other means for attacking the remote application and subsequently the user. Although, session hijacking is still considered the only thing you can do when having XSS, this is for from what is actually possible. The truth is that session hijacking is probably one of the least things the attacker will do for a number of reasons. The most obvious reason is that XSS attacks, although could be targeted, are not instant, like traditional overrun attacks where the attacker point the exploit to a remote location and gain access right away. For an XSS attack to be successful, sometimes it is required a certain period of time. It is highly unlikely that the attacker will wait all the time just to get a session which could be invalid a couple of moments later when the user clicks on the logout button. Remember, session hijacking is possible because concurrent sessions are possible [2].

The only and most effective way to attack when having XSS hole is to launch an attack right on place when the payload is evaluated. If the attacker needs to transfer funds or obtain sensitive information, they most probably will use the XMLHttpRequest object in the background, to automate the entire process. Once the operation is completed, the attacker could leave the user to continue with their normal work or maybe gain full control of the account my resetting the password and destroying the session by performing a logout operation [2]. 

What to do besides using HttpOnly flag (which is a lot)

Evaluate your specific situation to determine which techniques will work best for you. It is important to note that in all techniques, you are validating data that you receive from input and not your trusted script (use must check every single field). Essentially, prevention means that you follow good coding practice by running sanity checks on your input to your routines [6].

The following list outlines the general approaches to prevent cross-site scripting attacks:
  1. Encode output based on input parameters
  2. Filter input parameters for special characters.
  3. Filter output based on input parameters for special characters.
When you filter or encode, you must specify a character set for your Web pages to ensure that your filter is checking for the appropriate special characters. The data that is inserted into your Web pages should filter out byte sequences that are considered special based on the specific character set. A popular charset is ISO 8859-1, which was the default in early versions of HTML and HTTP. You must take into account localization issues when you change these parameters [6].


Code Example: HtmlEncode used to sanitized web fields [8].

Anti-XSS tools for .NET

So what was wrong with using System.Web.HttpUtility.HtmlEncode?  The problem with HttpUtility class is it was based upon deny-list (e.g. black listing approach) approach—in which I mentioned an earlier blog on the down fall with this approach—versus a Accept-only approach.  As a result of the deny-list approach the HttpUtility.HtmlEncode as only good against the following characters:

1. <
2. >
3. &
4. “
5. Characters with values 160-255 inclusive

The Microsoft Anti-XSS tool follows an Accept-only approach (e.g. white listing approach) in which this tool looks for a finite set of valid input and everything else is considered invalid.  This approach will provide a more comprehensive protection to XSS and reduce the ability to trick HttpUtility.HtmlEncode with canonical representations attacks [7].

You will find that the Anti-XSS tool works much like HttpUtility.HtmlEncode:

AntiXSSLibrary.HtmlEncode(string)

AntiXSSLibrary.URLEncode(string)


Now all characters will be encoded except for [7]:

1. a-z (lower case)
2. A-Z (upper case)
3. 0-9 (Numeric values)
4. , (Comma)
5. . (Period)
6. _ (Underscore)
7. - (dash) 8. (Space)—Except for URLEncode 

Do Not Rely on user input filtering but also at output user filtering

A common practice is for code to attempt to sanitize input by filtering out known unsafe characters (e.g. black listing known malicious input). Do not rely on this approach because malicious users can usually find an alternative means of bypassing your validation. While writing this article only IE supports HttpOnly, but there is a firefox plugin called HttpOnly5.0. It provides support for HttpOnly option to Firefox by encrypting cookies marked as HttpOnly on the browser side, so that JavaScript cannot read them.HttpOnly makes XSS much more harder to achive and Firefox3 is going probably to support HttpOnly option….. 

Reference:
  1. http://msdn2.microsoft.com/en-us/library/ms533046.aspx
  2. http://www.gnucitizen.org/blog/why-httponly-wont-protect-you/
  3. http://msdn.microsoft.com/en-us/library/system.net.cookie.httponly(VS.80).aspx
  4. http://blogs.msdn.com/dansellers/archive/2006/03/13/550947.aspx
  5. http://www.microsoft.com/technet/archive/security/news/crssite.mspx?mfr=true
  6. http://support.microsoft.com/default.aspx?scid=kb;en-us;252985&sd=tech
  7. http://blogs.msdn.com/dansellers/archive/2006/02/23/538187.aspx
  8. http://www.java2s.com/Code/ASP/Server/ServerHtmlEncodeVBnet.htm