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:
X-Frame-Options header (older but widely supported).
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:
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:
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.