Clickjacking relies on framing to trick legitimate clicks into triggering actions on a trusted site, often by layering a transparent iframe over a decoy page. Blocking unauthorized framing closes off common “one click” abuse paths such as changing account settings, confirming admin actions, or authorizing transactions.

Browsers enforce anti-framing policies via response headers. The legacy X-Frame-Options header provides simple controls like SAMEORIGIN and DENY, while modern browsers prefer Content-Security-Policy via the frame-ancestors directive when an allowlist is needed. In Apache, these headers are added with mod_headers and can be applied globally or scoped to a specific VirtualHost, Directory, or Location.

Header policies can break legitimate embeds such as same-site widgets, admin consoles in iframes, or third‑party portal integrations. Prefer Header always set so the policy also applies to error responses and redirects, and validate configuration syntax before restarting to avoid an accidental outage.

Steps to prevent clickjacking in Apache:

  1. Open a terminal with sudo privileges.
  2. Enable the headers module.
    $ sudo a2enmod headers
    Enabling module headers.
    To activate the new configuration, you need to run:
      systemctl restart apache2

    Debian, Ubuntu, and many openSUSE layouts provide a2enmod; RHEL-style layouts typically ship mod_headers enabled by default.

  3. Open the site configuration file for the VirtualHost that should send anti-framing headers.
    $ sudoedit /etc/apache2/sites-available/000-default.conf

    Header directives can also live in /etc/apache2/conf-available when the policy should apply to multiple sites.

  4. Locate the VirtualHost or Directory block that serves the pages to protect.
    <VirtualHost *:80>
        ServerName host.example.net
        DocumentRoot /var/www/html
     
        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
    </VirtualHost>
  5. Add an X-Frame-Options policy in the chosen scope.
    <VirtualHost *:80>
        ServerName host.example.net
        DocumentRoot /var/www/html
     
        Header always set X-Frame-Options "SAMEORIGIN"
     
        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
    </VirtualHost>

    DENY blocks all framing; SAMEORIGIN allows only the exact same origin (scheme, host, port), so subdomains such as app.internal.example are not permitted.

  6. Add a Content-Security-Policy frame-ancestors directive when an allowlist is required.
    Header always set Content-Security-Policy "frame-ancestors 'self'"

    If an application already emits a Content-Security-Policy header, merge frame-ancestors into the existing policy rather than emitting a second, conflicting header.

  7. Save the configuration file.
  8. Test the Apache configuration for syntax errors.
    $ sudo apache2ctl -t
    Syntax OK
  9. Restart the Apache service to apply the change.
    $ sudo systemctl restart apache2

    RHEL and CentOS typically use httpd as the service name.

  10. Verify the response includes the anti-framing headers.
    $ curl -I -H 'Host: host.example.net' http://127.0.0.1/
    HTTP/1.1 200 OK
    Date: Sat, 10 Jan 2026 05:50:10 GMT
    Server: Apache/2.4.58 (Ubuntu)
    X-Frame-Options: SAMEORIGIN
    Content-Security-Policy: frame-ancestors 'self'
    ##### snipped #####
    Content-Type: text/html

    Confirm the policy appears on the real site URL if a reverse proxy or CDN sits in front of Apache, since intermediaries can add, remove, or override headers.

  11. Verify the header is still present on an error response.
    $ curl -I -H 'Host: host.example.net' http://127.0.0.1/definitely-not-a-page
    HTTP/1.1 404 Not Found
    Date: Sat, 10 Jan 2026 05:50:10 GMT
    Server: Apache/2.4.58 (Ubuntu)
    X-Frame-Options: SAMEORIGIN
    Content-Security-Policy: frame-ancestors 'self'
    Content-Type: text/html; charset=iso-8859-1