Clickjacking: A Common Implementation Mistake Can Put Your Websites in Danger

Dingjie Yang

Last updated on: December 23, 2022

The X-Frame-Options HTTP response header is a common method to protect against the clickjacking vulnerability since it is easy to implement and configure, and all modern browsers support it. As awareness of clickjacking has grown in the past several years, I have seen more and more Qualys customers adopt X-Frame-Options to improve the security of their web applications.

However, I have also noticed there is a common implementation mistake that causes some web applications to be vulnerable to clickjacking attack even though they have X-Frame-Options configured. In this article, I describe the implementation mistake and show how to check your web applications to ensure X-Frame-Options is implemented correctly.

About Clickjacking and X-Frame-Options

As I wrote in my previous article, clickjacking is an attack that tricks a web user into clicking a button, a link or a picture, etc. that the web user didn’t intend to click, typically by overlaying the web page with a (typically transparent) iframe. The user thinks he is clicking the link on the legitimate page, but actually clicks an unseen overlaid link or button. This malicious technique can potentially expose confidential information or, less commonly, take control of the user’s computer. For example, on Facebook, a clickjack can lead to an unauthorized user spamming your entire network of friends from your account. We’ve known about clickjacking, also called “UI redress attacks,” for years now, which Robert Hansen and Jeremiah Grossman originally described in 2008.

So, how do X-Frame Options work? The X-Frame-Options HTTP response header can be used to specify whether or not the browser should be allowed to render content in a <frame> or <iframe>. If an iframe can’t be loaded in the browser and overlaid on the legitimate page, then a clickjacking attack is not possible.

Multiple X-Frame-Options in the Response Header

I have seen claims by Qualys customers that Qualys Web Application Scanning (WAS) flagged false positives of the Clickjacking vulnerability during scanning, even though they had deployed X-Frame-Options countermeasures in their web applications. These typically turn out to be true positives because of a common implementation error: more than one X-Frame-Options item presented in the response headers.

To understand the error, imagine making a request to http://foo.org and getting the following response headers with two X-Frame-Options fields:

HTTP/1.1 200 OK

Server: Apache-Coyote/1.1

X-FRAME-OPTIONS: SAMEORIGIN

Set-Cookie: JSESSIONID=E0BF8BA2829148A9D3C5370FB2A03820; Path=/; HttpOnly

X-FRAME-OPTIONS: SAMEORIGIN

X-Content-Type-Options: nosniff

X-XSS-Protection: 1; mode=block

When more than one X-Frame-Options item is used, browser engines will combine the multiple header fields into one by appending each subsequent field-value to the first when multiple message-headers fields with the same field name according to the HTTP RFC 2616 section 4.  It means browser engines will modify the previous response header into the following format.

HTTP/1.1 200 OK

Server: Apache-Coyote/1.1

Set-Cookie: JSESSIONID=E0BF8BA2829148A9D3C5370FB2A03820; Path=/; HttpOnly

X-FRAME-OPTIONS: SAMEORIGIN, SAMEORIGIN

X-Content-Type-Options: nosniff

X-XSS-Protection: 1; mode=block

According to RFC7034, only these three values, DENY, SAMEORIGIN and ALLOW FROM are valid values and they are mutually exclusive; that is, the header field must be set to exactly one of these three values. Some browsers will take the header item “X-Frame-Options: SAMEORIGIN, SAMEORIGIN” as invalid because the field value “SAMEORIGIN, SAMEORIGIN” is not any of the three values. As a consequence, the X-Frame-Options feature will not be effective in some browsers, such as Safari browser (6.0.5) and an attacker could launch clickjacking attacks against the victim when they are using an older version Safari browser to view the website.  I have tested this with Safari (5.1.7) on a Windows machine and Safari 6.0.5 on Mac.  Although Safari 7 (tested with Safari 7.1.7) has fixed this issue, it still imposes a danger if the user is using old Safari browsers.

How Common Are X-Frame-Options Implementation Errors?

I did some extra research on the Alexa Top 20 after deciding to write this article in order to check whether this kind of implementation error could also happen to some popular and big websites or if this is just a small issue caused by inexperienced developers.  The result was surprising.  I found out that several domains from one website in the Alexa Top 20 suffered from this error.

After some investigation, I found I could launch an attack using this vulnerability, and I am sure damage could be done if an attacker combined an attack against this vulnerability with some social engineering work. I’ve informed the owners of the vulnerable website, and they are working on mitigations.

Root Cause of the Implementation Error

Multiple reasons could lead to this kind of implementation errors. From the feedback of our customers that are suffering from these mistakes and my own developing experience, these two conditions will cause the more than one X-Frame-Options in the response header:

Condition 1: X-Frame-Options header is added in the source code and got deployed again in apache, IIS server

Condition 2: X-Frame-Options header is added in the source code or configure in apache/IIS server, meanwhile, load balance set “x-frame-options” again in its policy

For those in charge, I would advise them to check whether the response headers contain more than one X-Frame-Options headers if they are deploying X-Frame-Options to protect against a clickjacking attack.

Show Comments (17)

Comments

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

    1. Hi Mike,

          I personally prefer to add it in the server configuration because I don’t have to touch my source code when I want to change it in the future! But there is no preferred method in this area.

      Thanks

      Daniel

  1. A compliment for the blog:
    Another common implementation mistake when deploying x-frame-options is to add it in tag in the HTTP Content Header, something like, . We have observed several Qualys customers are using this ineffective countermeasure!
    This implementation has no effect in modern browsers and it is not recommended by OWAS either!

  2. Hi,

    I have recently added the X-Frames Options SAMEORIGIN, and after this I see that I get the below message when I try to access my site.

    “This content cannot be displayed in Frames”

    Please help me on how I can overcome this without removing the X-Frames

    1. Hi Srinivas,

      Could you please provide more details about your problem? If you add X-Frame-Options: SAMEORIGIN in your application. It means that the page can only be displayed in a frame on the same origin as the page itself. Are you trying to frame your page by a page from a different origin?

      Regards
      Daniel

  3. I had implemented the bellow code to solve Active Mixed Content Vulnerability. My main issue has been solved but it show another issue that says ‘HTTP Strict Transport Security (HSTS) header missing and max-age set below 120 days.’

    While it clear that max-Age is already set in code.

    switch (Request.Url.Scheme)
    {
    case “https”:
    Response.AddHeader(“Strict-Transport-Security”, “max-age=31536000”);
    break;
    case “http”:
    var path = “https://” + Request.Url.Host + Request.Url.PathAndQuery;
    Response.Status = “301 Moved Permanently”;
    Response.AddHeader(“Location”, path);
    break;
    }

    I had also implemented a fix in web.config but i am getting same issue by using them also. My config code is:

    Can anyone point out the problem in code or a way to solve them?

    1. Hi Jitendra,

      Could you please share the response header of the request to the vulnerable URL so that we could pinpoint the cause and potential solution for it?

      Thanks
      Daniel

  4. I am trying to append X-Frame-Options: ALLOW FORM “https://*.abc.com” and X-Frame-Options: Deny but its always defaulting to SAMEORIGIN for some reason. I tried it through config and code but the problem persists. I also tried to turn off the default X Frame Options setting by using

    protected void Application_Start()
    {

    System.Web.Helpers.AntiForgeryConfig.SuppressXFrameOptionsHeader = true;
    }
    And then doing this in the global.asax file but this is also no help
    protected void Application_BeginRequest()
    {
    Response.AddHeader(“X-Frame-Options”, “DENY”);
    }

    Can you please suggest me something. What I want to achieve is to be able to allow only certain(multiple though) domains to allow being opened on my app in an iframe. And since users are still using this app on Chrome and IE I need a solution which is compatible with both the browsers.

    1. Hi Apoorv,
      You should not append multiple options x-frame-options: allow from and x-frame-options:deny at the same time. Only one option is effective under the modern browser.
      Under your situation, I would suggest to use frame buster to allow certain domains to frame the application.

      Daniel

  5. Hi Apoorv,
    You should not append multiple options x-frame-options: allow from and x-frame-options:deny at the same time. Only one option is effective under the modern browser.
    Under your situation, I would suggest to use frame buster to allow certain domains to frame the application.

    Daniel

  6. Hi,
    I installed the npm xframe option in angular4 and the xframe option value is deny. but still iframe allowing my page inside it .How its happening.Please help

    1. Hi Mohana,

      Do you see the X-FRAME-OPTIONS: DENY in the response header when making a request to the page? It would be helpful if you could paste the response header.

  7. We had set X-Frame-Options=DENY in IIS. The Qualys scan was returning conflicting results, indicating both that X-Frame-Options was set – and it was not:

    150081 X-Frame-Options header is not set
    150082 Protection against Clickjacking vulnerability

    Using browser Developer Tools (Chrome Incognito to avoid any prior cache and cookies) to view X-Frame-Options setting in the Response Header, we saw that it contained multiple:

    +++++++++++++++++++++++++++++++++
    Server: Kestrel
    Set-Cookie: .AspNetCore.Antiforgery.iiHhD5m3M. . . fQ= -98; path=/XYZ; samesite=strict; httponly
    Strict-Transport-Security: max-age=2592000
    Transfer-Encoding: chunked
    X-Frame-Options: SAMEORIGIN
    X-Frame-Options: DENY
    +++++++++++++++++++++++++++++++++

    Googling “AspNetCore.Antiforgery sameorigin” provided the solution. By default AspNetCore() adds “SAMEORIGIN.” This creates a corrupt X-Frame-Options setting that QUALYS Scan detect as “Not Set.” (And since it is corrupt, it effectively is not set because it is not providing X-Frame protection.)

    Adding this in ConfigureServices() solved the problem:

    services.AddAntiforgery(o => o.SuppressXFrameOptionsHeader = true);

    REFERENCES

    https://stackoverflow.com/questions/40523565/asp-net-core-x-frame-options-strange-behavior

    https://docs.microsoft.com/en-us/aspnet/core/security/anti-request-forgery?view=aspnetcore-2.2

    SuppressXFrameOptionsHeader:
    Specifies whether to suppress generation of the X-Frame-Options header. By default, the header is generated with a value of “SAMEORIGIN”. Defaults to false.

  8. hi all, as i can see the x-frame-option header allready added ,when i tested through postman collection , but when i created a simple html page and tried to render my website in xyz.com , was able to load in it .
    can any one help me out in this?