A enhanced secure Blazor iFrame component with built-in origin validation, bidirectional messaging, navigation tracking, and comprehensive security features.
$ dotnet add package BlazorFrame
A security-first Blazor iframe component with automatic resizing, cross-frame messaging, and comprehensive Content Security Policy integration.
dotnet add package BlazorFrame
@using BlazorFrame
<!-- Simple iframe with automatic security -->
<BlazorFrame Src="https://example.com" />
<!-- Production-ready configuration with bidirectional communication and navigation tracking -->
<BlazorFrame @ref="iframeRef"
Src="https://widget.example.com"
EnableNavigationTracking="true"
SecurityOptions="@securityOptions"
OnValidatedMessage="HandleMessage"
OnNavigation="HandleNavigation"
OnSecurityViolation="HandleViolation" />
<button @onclick="SendDataToIframe">Send Data</button>
@code {
private BlazorFrame? iframeRef;
private readonly MessageSecurityOptions securityOptions = new MessageSecurityOptions()
.ForProduction() // Strict security settings
.WithBasicSandbox() // Enable iframe sandboxing
.RequireHttps(); // Enforce HTTPS transport
private Task HandleMessage(IframeMessage message)
{
Console.WriteLine($"Received message from {message.Origin}: {message.Data}");
return Task.CompletedTask;
}
private Task HandleNavigation(NavigationEvent navigation)
{
Console.WriteLine($"Navigation to: {navigation.Url}");
Console.WriteLine($"Query params: {string.Join(", ", navigation.QueryParameters)}");
return Task.CompletedTask;
}
private Task HandleViolation(IframeMessage violation)
{
Console.WriteLine($"Security violation: {violation.ValidationError}");
return Task.CompletedTask;
}
private async Task SendDataToIframe()
{
if (iframeRef != null)
{
await iframeRef.SendTypedMessageAsync("user-data", new { userId = 123, name = "John" });
}
}
}
// Development environment - relaxed security
var devOptions = new MessageSecurityOptions()
.ForDevelopment()
.WithPermissiveSandbox();
// Production environment - strict security
var prodOptions = new MessageSecurityOptions()
.ForProduction()
.WithStrictSandbox()
.ValidateAndThrow();
// Payment widgets - maximum security
var paymentOptions = new MessageSecurityOptions()
.ForPaymentWidget();
Control how the iframe automatically adjusts its height based on content:
<BlazorFrame Src="https://example.com"
EnableAutoResize="true"
ResizeOptions="@resizeOptions" />
@code {
// Custom resize configuration
private readonly ResizeOptions resizeOptions = new()
{
MinHeight = 200,
MaxHeight = 2000,
PollingInterval = 500,
DebounceMs = 100,
UseResizeObserver = true
};
// Or use built-in presets:
// ResizeOptions.Default - Balanced defaults
// ResizeOptions.Performance - Less frequent updates (better performance)
// ResizeOptions.Responsive - More frequent updates (smoother resizing)
}
| Property | Default | Description |
|---|---|---|
MinHeight | 100 | Minimum height in pixels |
MaxHeight | 50000 | Maximum height in pixels |
PollingInterval | 500 | Fallback polling interval (ms) when ResizeObserver unavailable |
DebounceMs | 100 | Debounce delay to prevent excessive updates (0 to disable) |
UseResizeObserver | true | Use ResizeObserver API when available |
Refresh iframe content without recreating the entire component - useful for PDFs, dynamic content, or cache-busting:
<BlazorFrame @ref="iframeRef" Src="@pdfUrl" />
<button @onclick="RefreshContent">Refresh</button>
<button @onclick="LoadNewDocument">Load New Document</button>
@code {
private BlazorFrame? iframeRef;
private string pdfUrl = "https://example.com/document.pdf";
// Reload the current content
private async Task RefreshContent()
{
if (iframeRef != null)
{
await iframeRef.ReloadAsync();
}
}
// Load a new URL with cache-busting
private async Task LoadNewDocument()
{
if (iframeRef != null)
{
var cacheBustedUrl = $"https://example.com/document.pdf?v={DateTime.UtcNow.Ticks}";
await iframeRef.ReloadAsync(cacheBustedUrl);
}
}
}
<BlazorFrame Src="https://widget.example.com"
CspOptions="@cspOptions"
OnCspHeaderGenerated="HandleCspGenerated" />
@code {
private readonly CspOptions cspOptions = new CspOptions()
.ForProduction()
.AllowFrameSources("https://widget.example.com")
.WithScriptNonce("secure-nonce-123");
private Task HandleCspGenerated(CspHeader cspHeader)
{
// Apply CSP header to HTTP response
// HttpContext.Response.Headers.Add(cspHeader.HeaderName, cspHeader.HeaderValue);
return Task.CompletedTask;
}
}
Comprehensive CSP integration for defense-in-depth security:
All iframe messages are automatically validated for:
| Level | Permissions | Use Case |
|---|---|---|
| None | No restrictions | Trusted content only |
| Basic | Scripts + same-origin | Most trusted widgets |
| Permissive | Scripts + same-origin + forms + popups | Interactive widgets |
| Strict | Scripts only (no same-origin) | Semi-trusted content |
| Paranoid | Empty sandbox (no permissions) | Untrusted content |
| Parameter | Type | Default | Description |
|---|---|---|---|
Src | string | "" | The URL to load in the iframe |
Width | string | "100%" | Width of the iframe |
Height | string | "600px" | Height of the iframe |
EnableAutoResize | bool | true | Enable automatic height adjustment |
ResizeOptions | ResizeOptions? | null | Configuration for auto-resize behavior |
EnableScroll | bool | false | Enable scrolling on the wrapper |
EnableNavigationTracking | bool | false | Track iframe navigation events |
AllowedOrigins | List<string>? | null | Allowed origins for postMessage |
SecurityOptions | MessageSecurityOptions | new() | Security configuration |
CspOptions | CspOptions? | null | Content Security Policy configuration |
| Method | Returns | Description |
|---|---|---|
ReloadAsync() | Task | Reloads the iframe content |
ReloadAsync(string newSrc) | Task | Reloads with a new source URL |
SendMessageAsync(object data, string? targetOrigin) | Task<bool> | Sends a message to the iframe |
SendTypedMessageAsync(string type, object? data, string? targetOrigin) | Task<bool> | Sends a typed message |
GetRecommendedCspHeader() | CspHeader? | Gets the recommended CSP header |
ValidateCspConfiguration() | CspValidationResult? | Validates the CSP configuration |
| Event | Type | Description |
|---|---|---|
OnLoad | EventCallback | Fired when iframe loads |
OnMessage | EventCallback<string> | Fired on message (raw JSON) |
OnValidatedMessage | EventCallback<IframeMessage> | Fired on validated message |
OnSecurityViolation | EventCallback<IframeMessage> | Fired on security violation |
OnNavigation | EventCallback<NavigationEvent> | Fired on navigation |
OnUrlChanged | EventCallback<string> | Fired on URL change |
OnMessageSent | EventCallback<string> | Fired when message sent |
OnMessageSendFailed | EventCallback<Exception> | Fired on send failure |
OnCspHeaderGenerated | EventCallback<CspHeader> | Fired when CSP generated |
OnInitializationError | EventCallback<Exception> | Fired on init failure |
Interactive Demo - Try different security configurations live
This project is licensed under the MIT License.
Built with :heart: for the Blazor community