Clickjacking (also known as UI redress attack) is a technique where attackers trick users into clicking something different from what they perceive, by overlaying transparent elements over legitimate buttons or links.
This demo shows how a clickjacking attack works. The transparent layer makes you think you're clicking "Claim Your Prize", but you're actually clicking "Delete Account".
The decoy layer (what the user sees) is shown on top of the victim layer (what the user actually interacts with).
Congratulations! You've been selected to receive a free gift card. Click the button below to claim your prize!
Warning: This action cannot be undone!
In this more realistic example, we have two separate web pages:
Clickjacking attacks can be used to trick users into:
The X-Frame-Options HTTP header can prevent your site from being loaded in an iframe:
// Server-side code (e.g., in Node.js) res.setHeader('X-Frame-Options', 'SAMEORIGIN');
Options include:
DENY
- Page cannot be displayed in a frame, regardless of the siteSAMEORIGIN
- Page can only be displayed in a frame on the same originALLOW-FROM uri
- Page can only be displayed in a frame on the specified originThe CSP header with frame-ancestors directive provides more flexibility:
// Server-side code res.setHeader('Content-Security-Policy', "frame-ancestors 'self'");
Options include:
frame-ancestors 'none'
- No embedding allowedframe-ancestors 'self'
- Only same-origin embedding allowedframe-ancestors example.com
- Allow embedding only on specified domainsClient-side JavaScript can detect and break out of iframes:
// Add this to your page if (top !== window) { top.location = window.location; }
Or a more comprehensive version:
(function() { // First, apply an initial CSS style to hide the content var style = document.createElement('style'); style.innerHTML = 'html { display: none !important; }'; document.head.appendChild(style); // Then check if we're being framed if (self === top) { // We're not in a frame, show the content var style = document.getElementsByTagName('style')[0]; document.head.removeChild(style); } else { // We're in a frame, break out top.location = self.location; } })();