XSS is the web vulnerability number 1 according to the OWASP project. If you developed web applications before, you know that its prevention exceeds escaping characters and using some regular expressions to filter out user input.
A good video here, show in 40 minutes XSS and why it’s more dangerous than what most of us think, check it out to understand what XSS is, although it explains only the XSS in the browser and not injected JavaScript like in PDF files or vulnerabilities in QuickTime and other software.
The best way to prevent XSS is to take advantage of the platform you are developing upon. Symphony has a built in functionalities to prevent XSS and CSRF. Today I will show a sneak preview of how the ASP.NET framework protect you from XSS attacks, this functionality has been around years before.
By default trying to inject a script in an ASP.NET form will trigger the exception System.Web.HttpRequestValidationException, as follows :
Although this protect you from XSS attacks but it shows your users an ugly exception and even some information that might be sensitive, for example the path of the page that caused the error and such, to solve this issue there are several solutions that I will show 2 among them.
1. Redirect to the default error page using the Web.config file:
As you maybe know already, you can redirect users to a default error page using only declarative syntax in the web.config file, and this includes also exceptions thrown when XSS attacks are encountered.
In the web.config file, insert this code in the <system.web> section:
<customErrors mode ="On" >
<error statusCode="500" redirect="error_page_handling_500_status.aspx" />
</customErrors>
For more detailed information about custom errors handling on ASP.NET you can refer here, for example you might want show errors only when connecting to the website remotely etc… You can provide as much error pages as you want mapping the appropriate HTTP error status, in this case we handle the 500 HTTP error code.
2. Override the on errors method and handle manually the response :
This method is more flexible and powerful, since it allows you to handle each exception separately, the only caveat is that you have to send the response HTML to the user yourself, because once an exception is raised, the ASP.NET execution pipeline breaks down. here is a sample of how to do this, in your page inert this code:
protected override void OnError(EventArgs e)
{
if (Server.GetLastError().GetBaseException() is
System.Web.HttpRequestValidationException)
{
Response.Clear();
Response.Write("<html><body>");
Response.Write("<h1> Your input has some unauthorized "
+ "markup, please provide a valid data </h1>");
Response.Write("</body></html>");
Response.StatusCode = 200;
Response.End();
//Response.Redirect("default.aspx");
}
}
Here you can notice that we check if the exception was raised by the detected XSS input, then we clear the response buffer and put some feed back to the user, of course you can send a full HTML page at this stage, and definitely you have to change the HTTP error status to 200 to indicate to the browser (or a JavaScript code using XHR) that the request was executed successfully.
Also notice the commented line, you can simply redirect the user to anther page, but this is not encouraged because users will have no clue about what happened.
Even normal HTML markup is detected as malicious code what to do?
Despite the flexible protection that the ASP.NET XSS filters provides, some times you need to accept such input from your users (<b> or <i> tags…), and hence, you need to tell ASP.NET not to check for XSS anymore. This is not an advised step and in 90% of the cases you will never need to do this.
To specify a page that doesn’t need XSS protection, you add this attribute to the page
ValidateRequest="false"
From now on, you have to validate yourself the user input, or even the output of data which is coming from outside sources like web services or a database. One step to never forget is escaping data when rendering it back to the user. This line do it nicely :
Server.HtmlEncode(userData);
Escaping data might sound as an ultimate solution to all the XSS problems, but it is not, most of the cases, programmers do not sanitize completely the data that they write to a database, and when displaying the same data, they consider it trusted, since it resides on their database, and this is when persistent XSS take place. So as an advice: never turn off the XSS validation unless you are 100% sure about what you are doing.
An example of this vulnerability can be found on the BlogEngine 1.3.0.0 open source project (tested here http://www.martani.net/2009/02/windows-7-part-3-internet-explorer-8.html), despite the fact that a brilliant team was working behind it, but… never trust user input.
user data is malicious unless proven otherwise.