Skip to content

Commit 74f4fd1

Browse files
authored
[Blazor] Fix multiple CSP policies (#55200)
* Fixes an issue where we would fail to apply the policy if another middleware already applied a policy.
1 parent 7d53092 commit 74f4fd1

File tree

3 files changed

+50
-1
lines changed

3 files changed

+50
-1
lines changed

src/Components/Server/src/Builder/ServerRazorComponentsEndpointConventionBuilderExtensions.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Microsoft.AspNetCore.Components.Server;
77
using Microsoft.AspNetCore.Components.Web;
88
using Microsoft.AspNetCore.SignalR;
9+
using Microsoft.Extensions.Primitives;
910

1011
namespace Microsoft.AspNetCore.Builder;
1112

@@ -54,7 +55,8 @@ public static RazorComponentsEndpointConventionBuilder AddInteractiveServerRende
5455
var original = b.RequestDelegate;
5556
b.RequestDelegate = async context =>
5657
{
57-
context.Response.Headers.Add("Content-Security-Policy", $"frame-ancestors {options.ContentSecurityFrameAncestorsPolicy}");
58+
var headers = context.Response.Headers;
59+
headers.ContentSecurityPolicy = StringValues.Concat(headers.ContentSecurityPolicy, $"frame-ancestors {options.ContentSecurityFrameAncestorsPolicy}");
5860
await original(context);
5961
};
6062
}

src/Components/test/E2ETest/ServerExecutionTests/WebSocketCompressionTests.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,43 @@ public async Task EmbeddingServerAppInsideIframe_WorksAsync()
5050
Assert.DoesNotContain("Content-Security-Policy", response.Headers.Select(h => h.Key));
5151
}
5252
}
53+
54+
[Fact]
55+
public async Task EmbeddingServerAppInsideIframe_WorksWithMultipleCspHeaders()
56+
{
57+
Navigate("/subdir/iframe?add-csp");
58+
59+
var logs = Browser.GetBrowserLogs(LogLevel.Severe);
60+
61+
Assert.Empty(logs);
62+
63+
// Get the iframe element from the page, and inspect its contents for a p element with id inside-iframe
64+
var iframe = Browser.FindElement(By.TagName("iframe"));
65+
Browser.SwitchTo().Frame(iframe);
66+
Browser.Exists(By.Id("inside-iframe"));
67+
68+
using var client = new HttpClient() { BaseAddress = _serverFixture.RootUri };
69+
var response = await client.GetAsync("/subdir/iframe?add-csp");
70+
response.EnsureSuccessStatusCode();
71+
72+
if (ExpectedPolicy != null)
73+
{
74+
Assert.Equal(
75+
[
76+
"script-src 'self' 'unsafe-inline'",
77+
$"frame-ancestors {ExpectedPolicy}"
78+
],
79+
response.Headers.GetValues("Content-Security-Policy"));
80+
}
81+
else
82+
{
83+
Assert.Equal(
84+
[
85+
"script-src 'self' 'unsafe-inline'"
86+
],
87+
response.Headers.GetValues("Content-Security-Policy"));
88+
}
89+
}
5390
}
5491

5592
public abstract partial class BlockedWebSocketCompressionTests(

src/Components/test/testassets/Components.TestServer/RazorComponentEndpointsStartup.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,16 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
6868
app.UseRouting();
6969
UseFakeAuthState(app);
7070
app.UseAntiforgery();
71+
72+
app.Use((ctx, nxt) =>
73+
{
74+
if (ctx.Request.Query.ContainsKey("add-csp"))
75+
{
76+
ctx.Response.Headers.Add("Content-Security-Policy", "script-src 'self' 'unsafe-inline'");
77+
}
78+
return nxt();
79+
});
80+
7181
_ = app.UseEndpoints(endpoints =>
7282
{
7383
_ = endpoints.MapRazorComponents<TRootComponent>()

0 commit comments

Comments
 (0)