SuperGeekery: A blog probably of interest only to nerds by John F Morton.

A blog prob­a­bly of inter­est only to nerds by John F Mor­ton.

Deter Clickjacking When You Can’t Set Security Headers By Using Javascript

Dont clickjack me

In this post we’ll talk about click­jack­ing, how to pro­tect your site visitor’s with robust sol­tu­ions, and a fall­back method when you’re unable to do it the nor­mal way. The need for this fall­back solu­tion is what inspired by a real-world sce­nario that I faced when a client need­ed a quick fix while the longer-term solu­tion was imple­ment­ed. 

What is click­jack­ing #

How do you pro­tect your users from click­jack­ing? First, you have to be aware of what click­jack­ing is. Let’s look at the Mozil​la​.org doc­u­men­ta­tion for a defin­tion. 

Click­jack­ing is an inter­­face-based attack that tricks web­site users into unwit­ting­ly click­ing on mali­cious links. In click­jack­ing, the attack­ers embed their mali­cious links into but­tons or legit­i­mate pages in a web­site.

It’s eas­i­er to under­stand what the means through an made-up exam­ple.

An exam­ple of click­jack­ing #

Imag­ine this web­page at was being hijacked from a sim­i­lar but mali­cious url, The mali­cious url could embed the legit­i­mate page with­in an iframe and then add addi­tion­al con­tent on top of the orig­i­nal con­tent. For exam­ple, the inter­net-bad-guy could add a but­ton to the page that says Sign up and get $1,000,000!” When a user clicks on the but­ton, a form would appear that col­lect­ed the user’s data for nefar­i­ous pur­pos­es. 😠

The X‑Frame-Options head­er #

As the cre­ator of, it’s easy for me to stop inter­net-bad-guys from embed­ding into an iframe by set­ting the site’s head­ers. The screen­shot below shows the head­ers that have been set on this web­page. There are quite a few head­ers, but I’ve high­light­ed one in par­tic­u­lar called X‑Frame-Options, which has been set to SAME­O­RI­GIN. This head­er is a rule that a brow­er will obey that says this web­page can only be used with­in an iframe on the same domain that it orig­i­nal­ly exists on.

Supergeekery iframe options headers

The X-Frame-Options header set to "SAMEORIGIN"

The Con­tent-Secu­ri­ty-Pol­i­cy head­er #

Mod­ern browsers sup­port a pow­er­ful and nuanced option with the Con­­tent-Secu­ri­­ty-Pol­i­­cy head­er. This is also an effec­tive solu­tion, but this head­ers is more com­pli­cat­ed to set up. I don’t need that lev­el of com­plex­i­ty so I still use the X‑Frame-Options head­er. Use which ever solu­tion works best for you.

Set­ting head­ers #

Set­ting head­ers can be com­pli­cat­ed because they are set on a serv­er lev­el and are depen­dent on how you’re build­ing your site. That means I can’t show you how to set head­ers for your project, but I can sug­gest some next steps. You might con­fig­ure them in your Apache con­fig­u­ra­tion, your Nginx con­fig­u­ra­tion, or maybe with a dynam­ic serv­er side lan­guage, like PHP or Node. On this site, I’ve set them up through my Nginx con­fig­u­ra­tion.

Test­ing #

You can see your head­ers in your Dev­Tools, as I showed in the first screen­shot. You can also use a test­ing tool to val­i­date that they’re set cor­rect­ly. Let’s take a look at this site in one of the test­ing tools:

Supergeekery iframe tester, shown in, can't be embedded in an iframe.

A fall­back solu­tion #

As a devel­op­er, you may find your­self in sit­u­a­tions where you can’t set your head­ers as you want. This is often because a client’s infrus­truc­ture is man­aged in a way that pro­tects that type of access. While you’re work­ing on a robust solu­tion, you can still add some pro­tec­tion for your users using Javascript. 

The fol­low­ing Javascript code block can be insert­ed into your pages and will attempt to pre­vent a page from being embed­ded in an iframe on anoth­er domain. It will allow your page to be put with­in an iframe on the same domain. I did that inten­tion­al­ly. You may have valid rea­son for using an iframe on your own con­tent.

  document.addEventListener("DOMContentLoaded", function () {
    if (top.location !== location) {
      document.body.innerHTML = ''; // Clears the existing content
      var noticeDiv = document.createElement('div'); // Create a new div element
      noticeDiv.innerHTML = 'Warning: This page cannot be embedded on another domain.'; // Set the message
      document.body.appendChild(noticeDiv); // Append the div to the body

I don’t intend to sug­gest that this is all you need to do, but it will help while you get your head­ers set prop­er­ly.