In short: Frameguard mitigates clickjacking attacks by setting the X-Frame-Options header.

The attack

Clickjacking attacks are pretty clever.

The attacker wants you to click something that you don’t actually want to click, and they do it by hiding the link/button behind something else that they can trick you into clicking on.

Let’s imagine that I’ve got a social network called Facepamphlet. I’m trying to get you to click “I love this” on my page, “Being Mean For No Reason”.

Screenshot of target page

You would never click the “I love this” button on your own, because you’re a kind person—you’re not a fan of being mean for no reason!

But let’s say I send you a website promising hundreds of photos of adorable puppies. You’d click something that let you see all of that! Cute puppies are great!

I send you a page that looks like this:

Screenshot of evil page with trick hidden

Of course you want to see cute puppies, so you click “Click here”. But, unbeknownst to you, there is an invisible iframe that you’ve just clicked on!

Screenshot of evil page with trick exposed

I’ve just “clickjacked” you and gotten you to click “I love this” on a page you hate!

Clickjacking can be used to get you to click anything you don’t want to. These things include unintentional endorsements on social networks, clicking advertisements, and if it’s very clever, tricking you into doing more complex things.

Read more:

The header

The X-Frame-Options header tells browsers to prevent your webpage from being put in an iframe. When browsers load iframes, they’ll check the value of the X-Frame-Options header and abort loading if it’s not allowed.

The header has three options:

  1. X-Frame-Options: DENY will prevent anyone from putting this page in an iframe.
  2. X-Frame-Options: SAMEORIGIN will prevent anyone from putting this page in an iframe unless it’s on the same origin. That generally means that you can put your own pages in iframes, but nobody else can.
  3. X-Frame-Options: ALLOW-FROM will allow to put your page in an iframe, but nobody else. (Unfortunately, you can only allow one domain.)

In the example above, Facepamphlet could mitigate clickjacking attacks by setting the X-Frame-Options header to DENY, preventing its pages from being put in iframes. Many websites do this.

If you aren’t expecting your pages to be put in iframes, setting this to DENY or SAMEORIGIN is probably a good idea because it limits your page’s attack surface.

The header has pretty good browser support: IE8+, Opera 10.50+, Safari 4+, Chrome 4.1+, and Firefox 3.6.9+. The ALLOW-FROM header option is not supported in many browsers. Those browsers will ignore the entire header, and the frame will be displayed.

Read more:

The code

Helmet’s Frameguard is a relatively simple middleware that will set the X-Frame-Options header to whatever you specify.

You can use this module as part of Helmet:

// Make sure you run "npm install helmet" to get the Helmet package.
const helmet = require('helmet')

app.use(helmet.frameguard({ action: 'sameorigin' }))

You can also use it as a standalone module:

// Make sure you run "npm install frameguard" to get the Frameguard package.
const frameguard = require('frameguard')

app.use(frameguard({ action: 'deny' }))

Once you’ve required it, you can use it in your apps:

// Don't allow me to be in ANY frames.
// Sets "X-Frame-Options: DENY".
app.use(frameguard({ action: 'deny' }))

// Only let me be framed by people of the same origin.
// Sets "X-Frame-Options: SAMEORIGIN".
app.use(frameguard({ action: 'sameorigin' }))
app.use(frameguard())  // defaults to sameorigin

// Allow from a specific host.
// Sets "X-Frame-Options: ALLOW-FROM".
  action: 'allow-from',
  domain: ''

This header is included in the default Helmet bundle and it uses its default value, SAMEORIGIN.