Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
Markdown Monster - The Markdown Editor for Windows

Getting around Chrome POST XSS Protection


:P
On this page:

I've been working on a small string conversion utility for turning strings into various code formats. Specifically, I've been writing a number of Visual Studio Code templates and VS code requires that templates are formatted into a JSON String Array, which means strings have to be split into lines with each line properly JSON formatted. This is a huge pain when creating large templates - especially HTML templates that contain lots of quotes that need to be encoded.

Long story short I threw together a simple Web Page String to Code Converter that handles this conversion (and a couple of others).

That Pesky XSS Protection

As you might expect my goal for these VS Code Templates was to create Code Snippets/Templates that could be quite large, HTML templates to be specific. So while creating an HTML template that includes an HTML form and some input fields I ran into a nasty error message in Chrome:

The error is: ERR_BLOCKED_BY_XSS_AUDITOR

Starting with Chrome 57, Chrome has started implementing an agressive XSS protection mechanism that prevents certain things from being posted to the server.

There's a lot of debate of whether this functionality belongs in the browser or not and in fact other modern browsers do not implement an XSS Auditor any more. At this point Chrome seems to be only one that triggers this. FireFox and Edge run the requests no problem without the header.

One important point to note is:

XSS or not Chrome Posts the data

Chrome does not prevent POSTing of the data to the server, but it prevents sending a response when the XSS Protection is triggered.

Thanks to Eric Lawrence for pointing that out. Presumably this behavior prevents you at least from echoing malicious content right back to the client - although that won't protect you if you return it on a subseqent request.

Working around XSS Protection

Although currently this is a browser specific feature implemented by Chrome, it turns out there are some standards based protections built into the HTTP spec that allow for this.

Specifically there is a X-XSS-Protection header that allows to tell the browser how to handle XXS protection. This options can explictly turn off the validation by setting the value to 0.

So in my simple Web page (an ASP.NET WebPages (cshtml) page) I can simply do this to get the page to work:

Response.Headers.Add("X-XSS-Protection", "0");

Et voila, the form gets posted without browser complaints in Chrome! Problem solved.

Be careful what you wish for

Request validation often is a good idea - until it isn't. For typical applications request validation is a good thing to avoid XSS attacks, although at the end of the day it's best just blanket HTMLEncode() all content (which BTW, my code above does yet it still triggers!).

Bypassing any default request validation is usually only good idea for special cases like the one I'm dealing with here, which explicitly requires me to post HTML, XML and code snippets that can contain the offending angle-brackets.

IOW - turn off validation selectively and not in a blanket move like for example adding X-XSS-Protection: 0 to your server's default headers. Or maybe you do, but give it some thought before you do and whether that makes sense.

ASP.NET Server Request Validation

While I'm here it's worth mentioning that server too is likely to reject this request. In ASP.NET WebPages the easy workaround is to use the Request.Unvalidated object to handle picking up the 'unsafe' request data:

var code = Request.Unvalidated.Form["code"];

This allows bypassing ASP.NET Request validation.

For WebForms you can use:

<@ Page validateRequest="false" %>

In MVC you can use the [ValidateInput(false)] attribute on controller actions to prevent validation:

[ValidateInput(false)]
public ActionResult Convert(CodeRequest request) 
{ ... }

If you're accessing raw Request data you can use this in MVC:

var rawComment = Request.Unvalidated().Form["code"];

IIS - HttpRuntime Settings

Ontop of that IIS also screws with request validation, and it often does so before ASP.NET gets control at all.

It's a good idea to turn that off in web.config and revert to the old behavior that delegated this functionality to the framework rather than the Web server itself:

<httpRuntime requestValidationMode="2.0"/>

Otherwise IIS fails the request before it ever hits the ASP.NET instance.

Summary

Request validation generally is a good idea - except on those very few occasions when it's not 😃. Definitely a problem when doing something like I am in this case which is posting code that almost always would trigger validation. But it can also bite you in regular business scenarios when somebody posts some legitamite angle brackets as part of text input. Rare, but it happens and it's usually hard to catch this initially as this becomes a runtime error.

Luckily there are workarounds. The X-XXS-Protection header solves Chromes XSS Auditor and various request validation options exists for server side code to be very specific about when you want to allow request validation to be bypassed.

Resources

Posted in ASP.NET  


West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024