Cyberis 4 October, 2023

Five-Minute Fix: Frameable Responses (Clickjacking)

Description

A 'Frameable Responses' or 'Clickjacking' vulnerability is reported when a web application allows its contents to be framed by another website.  This may be reported because of a lack of a 'Content-Security-Policy' HTTP response header, and/or a lack of an appropriate 'X-Frame-Options' HTTP response header.

When a page can be framed by another website, an attacker can load the target site in an iFrame on a website they control and render decoy layers over the victim site that is being framed, to trick a user into sending sensitive information or clicking a button that can cause an unintended action.

The overlay decoy page may look almost identical to the legitimate site, or it may have entirely different content, depending on the action the attacker wishes the victim to take when the page loads.  The decoy iFrame is generally sized to replicate the real site and therefore cover all content there.  The unsuspecting victim, when visiting a decoy site implementing a clickjacking attack, thinks that they are interacting with the visible buttons, whilst they are actually performing actions on the invisible page, in the layer below.

Clickjacking attacks can be mitigated both client side and server side.  When this vulnerability is reported against a web application, the relevant server-side countermeasures have not been implemented.

There are three different countermeasures that could be deployed by a web application. Framekiller JavaScript snippets within page code can prevent a page from being framed, but these are not always reliable across different browser technologies and therefore provide an incomplete fix.  The 'X-Frame-Options' response header offered partial protection against clickjacking when set to "DENY", but has now been replaced with the 'frame-ancestors' directive of Content Security Policy.  

Setting the directive of 'frame-ancestors' within a 'Content-Security-Policy' header is the recommended server-side mechanism to mitigate clickjacking.  Where 'frame-ancestors' is set in a 'Content-Security-Policy' and an 'X-Frame-Options' header is received in the same request, the frame-ancestors policy should be preferred by the browser, however due to variations within the implementation of these features by the different browser vendors this is not consistently enforced, therefore setting both headers with a consistent effect is likely to provide the most robust results and ensure maximum compatibility with the most commonly supported browsers.

Trusted external domains can be listed in the content security policy if necessary, that are permitted frame the application.


Risk/ Impact

If a web application is vulnerable to clickjacking, a user's private or sensitive information could be captured without their knowledge, such as credentials or payment information. The attack can also bypass cross-site request forgery provisions and cause unauthorised interactions with the victim application - for example, a victim might be inadvertently caused to make a purchase they did not intend, grant a 'like' on social media, or transfer money.

An attacker does this by loading the contents of the target application in an iFrame, on a site that the attacker controls, where a new interface that is fully transparent can be implemented. An example of this is on a login page. An attacker could frame the login page and overlay textboxes and login button that would then send the contents of the textboxes to the attacker, resulting in the victim having their credentials captured and stolen before the expected action takes place.

Below is a contrived example of clickjacking, with the iFrame outlined, to demonstrate how this attack works.

Image shows a login page being framed by an external domain

This example is simplified, with the overlay made almost transparent, and the username field moved slightly to the left, and layered text in red, to show how it is overlaid. When a victim types in their credentials, they are typing in the layered textboxes, which can be seen in this example as the text is slightly transparent, like the textboxes. However, in a real-world attack, the layered input fields would be transparent, with the text appearing as it would on the legitimate site.

Remediation

The best protection against clickjacking from the server-side is to set an appropriate 'Content-Security-Policy' 'frame-ancestors' directive in HTTP response headers which either prohibits all framing, or only allows framing from trusted domains.  For example, the headers may look like the following:

No domain can load the site in an iFrame

Content-Security-Policy: frame-ancestors 'none';

Only specified domains can load the site in an iFrame (one domain example)

Content-Security-Policy: frame-ancestors 'self' https://www.example.org;

Only specified domains can load the site in an iFrame (multiple domains example)

Content-Security-Policy: frame-ancestors 'self' https://example.org https://example.com https://store.example.com;

Note that Content-Security-Policy is not just a countermeasure for clickjacking.  Content-Security-Policy headers are recommended in many cases to help protect against other common web application attacks, such as cross-site scripting by blocking the loading of inline JavaScript and dynamic CSS blocks from untrusted sources.  If implementing Content-Security-Policy for the first time in mitigation of a clickjacking vulnerability, other elements of the content security policy should also be implemented.

X-Frame-Options is a secondary response header which can be used to provide additional protection.  Though it is now deprecated, setting the X-Frame-Options header provides broad protection against this attack even with older browsers that may not support Content-Security-Policy headers.  Setting this to 'DENY' prevents all framing, regardless of the origin of the parent frame, whereas setting this to 'SAMEORIGIN' allows framing where the parent frame has the same origin as the loaded resource, denying other scenarios.


Apache:

Ensure that the headers module is added to the global server configuration file (e.g., /etc/apache2/httpd.conf)

LoadModule headers_module modules/mod_headers.so

Configure the header settings per enabled website - configuration files are usually in /etc/apache2/sites-enabled/

Add the following to each site configuration files, inside the VirtualHost section:

# Set Content-Security-Policy to prevent framing:
Header always set Content-Security-Policy "frame-ancestors 'none';"
Header always set X-Frame-Options “DENY”

NGINX: 

Add the following to the top-level server block for the server within the NGINX configuration files:

add_header Content-Security-Policy "frame-ancestors 'none';" always;
add_header X-Frame-Options DENY always;

NGINX configuration blocks inherit add_header directives from their enclosing blocks, so if location blocks include other add_header directives, the headers will also need to be redeclared within this block.

IIS:

Configure IIS:

<system.webServer>
 …
 <httpProtocol>
   <customHeaders>
    <add name="Content-Security-Policy" value="frame-ancestors 'none';" />
         <add name="X-Frame-Options" value="DENY" />
   </customHeaders>
 </httpProtocol>
 …
</system.webServer>

Systems should be thoroughly tested before deploying the fixes in a live environment.


References:

If you would like to learn more, or understand the full business and security risk to changes you are performing, we recommend the following references.

Improve your security

Our experienced team will identify and address your most critical information security concerns.