I need a generic method for preventing XSS attacks in ASP.NET. The approach I came up with is a ValidateRequest method that evaluates the HttpRequest for any potential issues, and if issues are found, redirect the user to the same page, but in a away that is not threatening to the application. (Source code below)
While I know this method will prevent most XSS attacks, I am not certain that I am adequately preventing all possible attacks while also minimizing false positives. So,
what is the most effective way to adequately prevent all possible attacks, while minimizing false positives? Are there changes I should make to the helper class below, or is there an alternative approach or third party library that offers something more convincing?
public static class XssSecurity
{
public const string PotentialXssAttackExpression = "(http(s)*(%3a|:))|(ftp(s)*(%3a|:))|(javascript)|(alert)|(((\\%3C) <)[^\n]+((\\%3E) >))";
private static readonly Regex PotentialXssAttackRegex = new Regex(PotentialXssAttackExpression, RegexOptions.IgnoreCase);
public static bool IsPotentialXssAttack(this HttpRequest request)
{
if(request != null)
{
string query = request.QueryString.ToString();
if(!string.IsNullOrEmpty(query) && PotentialXssAttackRegex.IsMatch(query))
return true;
if(request.HttpMethod.Equals("post", StringComparison.InvariantCultureIgnoreCase))
{
string form = request.Form.ToString();
if (!string.IsNullOrEmpty(form) && PotentialXssAttackRegex.IsMatch(form))
return true;
}
if(request.Cookies.Count > 0)
{
foreach(HttpCookie cookie in request.Cookies)
{
if(PotentialXssAttackRegex.IsMatch(cookie.Value))
{
return true;
}
}
}
}
return false;
}
public static void ValidateRequest(this HttpContext context, string redirectToPath = null)
{
if(context == null || !context.Request.IsPotentialXssAttack()) return;
// expire all cookies
foreach(HttpCookie cookie in context.Request.Cookies)
{
cookie.Expires = DateTime.Now.Subtract(TimeSpan.FromDays(1));
context.Response.Cookies.Set(cookie);
}
// redirect to safe path
bool redirected = false;
if(redirectToPath != null)
{
try
{
context.Response.Redirect(redirectToPath,true);
redirected = true;
}
catch
{
redirected = false;
}
}
if (redirected)
return;
string safeUrl = context.Request.Url.AbsolutePath.Replace(context.Request.Url.Query, string.Empty);
context.Response.Redirect(safeUrl,true);
}
}