Improper Restriction of Rendered UI Layers or Frames

Description

Improper Restriction of Rendered UI Layers or Frames occurs when a web application does not restrict or incorrectly restricts frame objects or UI layers that belong to another application or domain. This enables "Clickjacking" attacks where an attacker overlays transparent or opaque frames over legitimate UI elements, tricking users into clicking on malicious content while believing they are interacting with the legitimate site. Attackers can use this to steal credentials, perform unauthorized actions, or trick users into enabling dangerous features.

Risk

Clickjacking attacks can have severe consequences including unauthorized fund transfers, social media account compromises, webcam/microphone activation, and malware installation through drive-by downloads. Notable attacks have targeted Facebook's "Like" button (likejacking), Twitter's "Follow" button, and banking applications. Without proper frame restrictions, any authenticated action a user can perform can potentially be hijacked. Modern browsers have implemented some protections, but applications must still explicitly opt-in to these protections.

Solution

Implement X-Frame-Options header with DENY or SAMEORIGIN. Use Content-Security-Policy (CSP) frame-ancestors directive for more granular control. Implement frame-busting JavaScript as defense-in-depth (though it can be bypassed). Use SameSite cookie attribute to prevent cookies from being sent in framed contexts. For sensitive operations, implement additional confirmation steps that cannot be clickjacked (e.g., re-authentication, CAPTCHA).

Common Consequences

ImpactDetails
IntegrityScope: Unauthorized Actions

Users unknowingly perform actions like changing settings, making purchases, or granting permissions.
ConfidentialityScope: Credential Theft

Login forms can be overlaid to steal credentials.
Access ControlScope: Permission Hijacking

Attackers can trick users into granting permissions for camera, microphone, or geolocation.

Example Code + Solution Code

Vulnerable Code

<!-- VULNERABLE: No clickjacking protection -->
<!-- This page can be embedded in any iframe -->
<!DOCTYPE html>
<html>
<head>
    <title>Banking Transfer</title>
</head>
<body>
    <form action="/transfer" method="POST">
        <input type="hidden" name="to" value="attacker-account">
        <input type="hidden" name="amount" value="10000">
        <button type="submit">Click here for a free prize!</button>
    </form>
</body>
</html>
# VULNERABLE: No X-Frame-Options header
from flask import Flask, render_template

@app.route('/settings')
def settings():
    # No frame protection - can be embedded and clickjacked
    return render_template('settings.html')
// VULNERABLE: Ineffective frame-busting (can be bypassed)
if (top != self) {
    top.location = self.location;  // Can be blocked by sandbox attribute
}

Fixed Code

# SAFE: X-Frame-Options and CSP headers
from flask import Flask, make_response

@app.after_request
def add_security_headers(response):
    # Prevent framing entirely
    response.headers['X-Frame-Options'] = 'DENY'

    # Or allow same origin only
    # response.headers['X-Frame-Options'] = 'SAMEORIGIN'

    # CSP frame-ancestors (more flexible)
    response.headers['Content-Security-Policy'] = "frame-ancestors 'none';"

    return response

# For specific trusted domains:
# response.headers['Content-Security-Policy'] = "frame-ancestors 'self' https://trusted.example.com;"
// SAFE: Robust frame-busting with sandbox detection
(function() {
    // Check if we're in a frame
    if (self !== top) {
        // Check if we can break out
        try {
            // Attempt to access parent - will throw if cross-origin
            if (top.location.hostname !== self.location.hostname) {
                // We're framed by a different origin - redirect
                top.location = self.location;
            }
        } catch (e) {
            // Cross-origin frame detected
            // Hide content and show warning
            document.body.innerHTML = '<h1>This content cannot be displayed in a frame</h1>';
        }
    }
})();

// SAFE: Additional protection for sensitive actions
function performSensitiveAction() {
    // Require re-confirmation that can't be clickjacked
    const confirmed = prompt('Type "CONFIRM" to proceed with this action:');
    if (confirmed !== 'CONFIRM') {
        return false;
    }
    // Proceed with action
}
<!-- SAFE: Server-side headers plus client-side protection -->
<!DOCTYPE html>
<html>
<head>
    <title>Secure Page</title>
    <style>
        /* Hide content until JS confirms we're not framed */
        html { display: none; }
    </style>
    <script>
        if (self === top) {
            document.documentElement.style.display = 'block';
        } else {
            // Framed - don't show content
            top.location = self.location;
        }
    </script>
</head>
<body>
    <!-- Content only shown if not framed -->
</body>
</html>
// SAFE: Spring Security configuration
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .headers()
                .frameOptions()
                    .deny()  // X-Frame-Options: DENY
                .and()
                .contentSecurityPolicy("frame-ancestors 'none';");
    }
}

// Or using filter for non-Spring applications
@WebFilter("/*")
public class ClickjackingFilter implements Filter {
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("X-Frame-Options", "DENY");
        response.setHeader("Content-Security-Policy", "frame-ancestors 'none';");
        chain.doFilter(req, res);
    }
}

Exploited in the Wild

Facebook Likejacking (2010-Present)

Attackers overlay invisible Facebook "Like" buttons over enticing content, causing users to unknowingly like pages or share content, used for spreading malware and scams.

Twitter Clickjacking (2009)

Attackers used clickjacking to trick Twitter users into posting tweets or following accounts without their knowledge, spreading malicious links.

Adobe Flash Settings Hijacking

Clickjacking attacks targeted Adobe Flash's settings manager to enable webcam and microphone access without user awareness.


Tools to test/exploit


CVE Examples


References

  1. MITRE. "CWE-1021: Improper Restriction of Rendered UI Layers or Frames." https://cwe.mitre.org/data/definitions/1021.html

  2. OWASP. "Clickjacking Defense Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/Clickjacking_Defense_Cheat_Sheet.html