Skip to content

Commit

Permalink
Fix broken find token image in HTTP (#3635)
Browse files Browse the repository at this point in the history
  • Loading branch information
JamesNK authored Apr 12, 2024
1 parent 8ff7c93 commit e56c56e
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 4 deletions.
26 changes: 22 additions & 4 deletions src/Aspire.Dashboard/Model/BrowserSecurityHeadersMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,40 @@ namespace Aspire.Dashboard.Model;
internal sealed class BrowserSecurityHeadersMiddleware
{
private readonly RequestDelegate _next;
private readonly string _cspContent;
private readonly string _cspContentHttp;
private readonly string _cspContentHttps;

public BrowserSecurityHeadersMiddleware(RequestDelegate next, IHostEnvironment environment)
{
_next = next;

_cspContentHttp = GenerateCspContent(environment, isHttps: false);
_cspContentHttps = GenerateCspContent(environment, isHttps: true);
}

private static string GenerateCspContent(IHostEnvironment environment, bool isHttps)
{
// Based on Blazor documentation recommendations:
// https://learn.microsoft.com/aspnet/core/blazor/security/content-security-policy#server-side-blazor-apps
// Changes:
// - style-src adds inline styles as they're used extensively by Blazor FluentUI.
// - frame-src none added to prevent nesting in iframe.
var content = "base-uri 'self'; " +
"img-src data: https:; " +
"object-src 'none'; " +
"script-src 'self'; " +
"style-src 'self' 'unsafe-inline'; " +
"frame-src 'none';";

if (isHttps)
{
// Only allow https images when the site is served over https.
content += " img-src data: https:;";
}
else
{
content += " img-src data: http: https:;";
}

// default-src limits where content can fetched from.
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/default-src
// This value stops BrowserLink and automatic hot reload from working in development.
Expand All @@ -41,15 +57,17 @@ public BrowserSecurityHeadersMiddleware(RequestDelegate next, IHostEnvironment e
content += " default-src 'self';";
}

_cspContent = content;
return content;
}

public Task InvokeAsync(HttpContext context)
{
// Don't set browser security headers on OTLP requests.
if (context.Features.Get<IOtlpConnectionFeature>() == null)
{
context.Response.Headers.ContentSecurityPolicy = _cspContent;
context.Response.Headers.ContentSecurityPolicy = context.Request.IsHttps
? _cspContentHttps
: _cspContentHttp;

// Recommended best practice value: https://web.dev/articles/referrer-best-practices
context.Response.Headers["Referrer-Policy"] = "strict-origin-when-cross-origin";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,24 @@ public async Task InvokeAsync_Production_DenyExternalFetch()
Assert.Contains("default-src", httpContext.Response.Headers.ContentSecurityPolicy.ToString());
}

[Theory]
[InlineData("https", "img-src data: https:;")]
[InlineData("http", "img-src data: http: https:;")]
public async Task InvokeAsync_Scheme_ImageSourceChangesOnScheme(string scheme, string expectedContent)
{
// Arrange
var middleware = CreateMiddleware(environmentName: "Production");
var httpContext = new DefaultHttpContext();
httpContext.Request.Scheme = scheme;

// Act
await middleware.InvokeAsync(httpContext);

// Assert
Assert.NotEqual(StringValues.Empty, httpContext.Response.Headers.ContentSecurityPolicy);
Assert.Contains(expectedContent, httpContext.Response.Headers.ContentSecurityPolicy.ToString());
}

[Fact]
public async Task InvokeAsync_Otlp_NotAdded()
{
Expand Down

0 comments on commit e56c56e

Please sign in to comment.