Interstell, Inc.

Security, Application Security, and Software Research

XSS – Sometimes a Threat Needs a Specific Response

Ordinarily, I try to stay away from defending against specific attacks. Instead, I prefer to write software that is resistant to attacks using generalized defenses like input protections. However, there are some cases where an attack is so pervasive and its results so devastating that it deserves its own set of defenses.

Cross site scripting (XSS) is one such attack.

Sitting at #3 in OWASP’s most recent top ten vulnerabilities, XSS is at once easy and astoundingly hard to protect against. It’s easy because in many cases, simple input sanitization like we’ve been discussing on this blog can reduce your exposure. Astoundingly hard because there are so many attack vectors, and input controls only address some of them.

In this post, I’ll present some techniques for shoring up your application’s defenses against XSS.

XSS attacks can strike anytime, anywhere (well, anywhere connected to the Internet). But you can protect yourself!

X-XSS-Protection: Cobbled Together…

The first technique seems to almost have been thrown together in desperation. As XSS took its place in the OWASP top 10 and refused to leave, it became obvious that developers just weren’t giving it the attention it needed. So, browser manufacturers tried to take steps to protect applications. They came up with X-XSS-Protection. All browsers don’t support it, but Internet Explorer after version 8, Chrome, Opera, Edge, and Safari do support it, so it’s worth understanding.

X-XSS-Protection involves the browser’s built-in XSS protection. It’s only as good as the vendor’s implementation, but the goal, like HTMLPurifier, is to detect an XSS attack and take steps against it. Is it perfect? No. Is it better nothing? Absolutely! It has several options that control how it reacts to a detected attack, but I’m most interested in the default:

X-XSS-Protection: 1

This turns the browser’s protections on. In this mode, the browser will attempt to detect and neutralize any XSS attacks. It will also continue displaying the page. This seems like a good compromise. If you trust the X-XSS-Protection directive to do its job, then we might as well trust it to neutralize the attack and not inconvenience our customers.

There are a couple of other options, like:

X-XSS-Protection: 1; mode=block

In that mode, if the browser detects an XSS attack, it will stop rendering the page. That might seem more safe, but think about it: if we trust X-XSS-Protection to detect the attack, then we know it’ll block said attack. In other words, if we trust X-XSS-Protection enough to enable it, we might as well trust it to neutralize the attack. Of course, specific circumstances might incline you to use this option, and that’s fine! Let your experience be your guide!

Another option would be to log a report if X-XSS-Protection detects an attack. For example:

X-XSS-Protection: 1; report=/asfg_protectinginput_php/warntheworld.php

In this case, the browser will attempt to sanitize the XSS and then report the error to the URI you provide. If your company has no security team monitoring the network, applications servers, and applications, it might be a good idea to set this so you get warnings if malicious actors try to use your site to launch XSS attacks.

You can set X-XSS-Protection in two ways. For PHP, you’d use this before you send any HTML to the browser:

header("X-XSS-Protection: 1");

For Java, you’d do this at the top of a JSP or in a servlet before sending HTML to the client:

response.addHeader("X-XSS-Protection", "1");

Allow JavaScript libraries fro known safe repositories; deny others. Easy! But be cautious you don’t deny a source you need!

Attacks from Afar (or from A-near…)

Some XSS attack vectors involve HTML Frames. So, the browser community has evolved a means to protect against the introduction of scripting from a frame: X-Frame-Options.

Sometimes, an attacker will attempt to invisibly insert a FRAME into your site (maybe by taking advantage of unsanitized input). That FRAME, which may be invisible to the user, could contain a tiny JavaScript stub into your input fields. That tiny stub might be something like:

<script src=""/>

You can stop that sort of nonsense with X-Frame-Options. The code would look like this:

 X-Frame-Options: SAMEORIGIN 

It’s helpful, but it’s also dangerous. A lot of frameworks in use today, like Bootstrap or AngularJS, support linking to content delivery network (CDN) for the official JavaScript libraries. If you’re not careful with X-Frame-Options and your application uses FRAMEs, you might deny your application the libraries it needs to function!  Fortunately, X-Frame-Options can whitelist the sites you want. For example:

 X-Frame-Options: ALLOW-FROM 

This example would let me load FRAMES containing JavaScript libraries from all day without raising an error. Of course, if an attacker does manage to get around your input sanitization and somehow injects the tiny stub that refers to their nefarious JavaScript library, the browser will reject the attempt by policy. That’s a good thing! The Mozilla Developer Network says that this header is supported in different ways by different browsers:

  1. Chrome: Basic
  2. Edge: Full
  3. FireFox (1.9.2 and after, Basic; 18 and after, full)
  4. Internet Explorer (starting with 8.0)
  5. Opera (basic)
  6. Safari (basic, after 4.0; otherwise, full)

For PHP, you can enable it with this function (before sending any HTML to the client):

 header("X-Content-Security-Policy: ALLOW-FROM"); 

From a Tomcat servlet, you can do about the same thing with something like this:


If you plan ahead, X-Frame-Options can give you another layer of protection.

Encoding is another layer of protection. And, as Shrek has pointed out, layers can be good!

Tag-Teaming with the Browser

We can help the browser protect itself another way: by explicitly telling it what character sets (encoding type) our web application is using. There are multiple character sets that are well-described here, and when a browser first hits your site, it has no idea which one you’re using. Why should you be explicit? Because malicious actors have learned to take advantage of a browser’s good nature. If you don’t set the encoding type on your server application, the browser will try to guess. Generally speaking, it guesses well, but malicious actors have learned how to use non-default encoding to fool the browser into executing XSS attacks.

Setting the character set is pretty easy: just use a META tag in the HTML HEAD. The same technique would work in PHP or Java/Tomcat:

<title>Explicitly Setting the App’s Encoding</title>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">

 When to Deviate from Conviction

Like I said the opening paragraph, I prefer to protect my applications by applying broad security principles like input sanitization and validation. That approach protects my applications against many different kinds of attacks, even ones that I don’t anticipate. There are times, though, when a specific kind of attack is so pervasive and dangerous that it warrants its own kinds of protection. XSS is just one of those kinds of attacks. The techniques I’ve summarized in this post should help you protect your server and your customers from XSS attacks.

Important note: None of these techniques replace input sanitization or other forms of protection. Rather, it augments them. Without input sanitization, your application is just cannon fodder for attackers, so please don’t interpret this post as a suggestion not to use it!

Have you used either X-XSS-Protection or X-Frame-Options? What’s your experience been? Let me know in the comments!

by Terrance A. Crow

Terrance has been writing professionally since the late 1990s — yes, he’s been writing since the last century! Though he started writing about programming techniques and security for Lotus Notes Domino, he went on to write about Microsoft technologies like SQL Server, ActiveX Data Objects, and C#. He now focuses on application security for professional developers because… Well, you’ve watched the news. You know why! 


Categories: Application Security

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.