ASP.NET Core  

Clickjacking Protection with X-Frame-Options and CSP in ASP.NET Core

What is clickjacking?

Clickjacking (UI redressing) is an attack where a malicious site embeds your application inside a hidden or transparent <iframe> and tricks users into clicking buttons or links without realizing it.

Example scenario:

  • A banking site’s "Transfer Money" button is overlaid inside an invisible frame.

  • The user thinks they’re clicking a harmless button, but they actually authorize a money transfer.

To prevent this, we must restrict how (or if) our pages can be embedded in iframes.

Defense Mechanisms in ASP.NET Core

ASP.NET Core supports two main methods for clickjacking protection:

  1. X-Frame-Options header (older but widely supported).

  2. Content Security Policy (CSP) with frame-ancestors directive (modern replacement).

It’s best to use CSP frame-ancestors, but including both ensures compatibility with legacy browsers.

1. Using X-Frame-Options

The X-Frame-Options header tells the browser whether a page can be displayed in a <frame>, <iframe>, or <object>.

Options

  • DENY → Prevents all framing.

  • SAMEORIGIN → Allows framing only from the same domain.

  • ALLOW-FROM uri → Allows framing only from a specific origin (deprecated, limited support).

Example in ASP.NET Core middleware (Program.cs)

app.Use(async (context, next) =>
{
    context.Response.Headers.Add("X-Frame-Options", "SAMEORIGIN");
    await next();
});

2. Using CSP frame-ancestors

CSP provides a more flexible and modern way to control embedding.

Example policy

Content-Security-Policy: frame-ancestors 'self' https://trustedpartner.com

This means:

  • Only the same origin ('self') and https://trustedpartner.com can embed your pages.

  • All other attempts will be blocked.

ASP.NET Core middleware

app.Use(async (context, next) =>
{
    context.Response.Headers.Add("Content-Security-Policy",
        "default-src 'self'; frame-ancestors 'self' https://trustedpartner.com");
    await next();
});

3. Using NWebsec (Recommended)

Instead of writing headers manually, use NWebsec middleware, which integrates well with ASP.NET Core.

Install

dotnet add package NWebsec.AspNetCore.Middleware

Configure in Program.cs

app.UseXfo(options => options.SameOrigin()); // X-Frame-Options: SAMEORIGIN

app.UseCsp(options => options
    .FrameAncestors(s => s.Self().CustomSources("https://trustedpartner.com"))
);

This ensures both X-Frame-Options and CSP frame-ancestors are active.

4. When to Allow Framing

In some cases, you may intentionally allow embedding, such as:

  • Integrating your app inside a trusted parent site.

  • Using widgets, dashboards, or third-party portals.

In such cases:

  • Avoid DENY.

  • Use SAMEORIGIN or a specific trusted domain with CSP.

Example for allowing only your own site:

app.UseCsp(options => options.FrameAncestors(s => s.Self()));

5. Testing Clickjacking Protection

You can test protections by trying to embed your site in an <iframe>:

<iframe src="https://yoursite.com" width="600" height="400"></iframe>

If protections are correctly set, the page will not render inside the frame. Instead, you’ll see a blank page or a browser error in the developer console.

Best Practices

  • Always set X-Frame-Options (for old browsers).

  • Use CSP frame-ancestors (modern and flexible).

  • Only allow trusted domains when framing is necessary.

  • Test with different browsers.

  • Combine with other headers (X-Content-Type-Options, X-XSS-Protection, etc.) for better overall security.

Conclusion

Clickjacking attacks exploit iframes to trick users into unintended actions. ASP.NET Core apps can defend against this by setting X-Frame-Options and CSP frame-ancestors headers. Using libraries like NWebsec makes implementation easier and more robust. By combining these protections, you ensure your Razor Pages or MVC applications cannot be maliciously embedded and abused.