Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Piranha middleware breaks response headers. #1899

Open
Neutrino-Sunset opened this issue Jul 10, 2022 · 1 comment
Open

Piranha middleware breaks response headers. #1899

Neutrino-Sunset opened this issue Jul 10, 2022 · 1 comment
Labels

Comments

@Neutrino-Sunset
Copy link

This initialization code correctly adds the specified security headers to all responses.

var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseKestrel(option => option.AddServerHeader = false);
builder.Services.AddRazorPages();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
   app.UseExceptionHandler("/Error");
   app.UseHsts();
}

app.UseHttpsRedirection();

app.Use(async (context, next) =>
{
   context.Response.Headers.Add("Content-Security-Policy", "default-src 'self';");
   context.Response.Headers.Add("X-XSS-Protection", "1; mode=block");
   context.Response.Headers.Add("X-Content-Type-Options", "nosniff");
   context.Response.Headers.Add("X-Frame-Options", "SAMEORIGIN");
   await next.Invoke();
});

app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();

app.Run();

This same code with minimal Piranha initialization code does not work. The security headers are correctly added for page requests, but for all other requests (e.g. css, scripts, images and all other resources) the headers are not added.

var builder = WebApplication.CreateBuilder(args);

builder.AddPiranha(options =>
{
   options.UseCms();
   options.UseFileStorage(naming: Piranha.Local.FileStorageNaming.UniqueFolderNames);
   options.UseEF<SQLiteDb>(db =>
       db.UseSqlite("Filename=./PiranhaWeb.db"));
});

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
   app.UseExceptionHandler("/Error");
   app.UseHsts();
}

app.UseHttpsRedirection();

app.Use(async (context, next) =>
{
   context.Response.Headers.Add("Content-Security-Policy", "default-src 'self';");
   context.Response.Headers.Add("X-XSS-Protection", "1; mode=block");
   context.Response.Headers.Add("X-Content-Type-Options", "nosniff");
   context.Response.Headers.Add("X-Frame-Options", "SAMEORIGIN");
   await next.Invoke();
});

app.MapRazorPages();

app.UsePiranha(options =>
{
   App.Init(options.Api);
});

app.Run();

Seems like a bug to me.

Full working repo here

@vjacquet
Copy link
Contributor

vjacquet commented Sep 6, 2022

My guess is that the problem is within options.UseCms() because it registers PiranhaStartupFilter

serviceBuilder.Services.AddTransient<IStartupFilter, PiranhaStartupFilter>();

that calls the static file middleware at the beginning of the pipeline, so it runs before your own middleware.
builder
.UseSecurityMiddleware()
.UseStaticFiles()
.UseMiddleware<RoutingMiddleware>()
.UseMiddleware<SitemapMiddleware>();
next(builder);

May be you could try and implement you own IStartupFilter and register it in the services before piranha's.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddTransient<IStartupFilter, MySecurityStartupFilter>();
builder.AddPiranha(options =>
{
   options.UseCms();
   ...

Where MySecurityStartupFilter is

    class MySecurityStartupFilter  : IStartupFilter
    {
        public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
        {
            return builder =>
            {
                builder.Use(async (context, next) =>
                {
                    context.Response.Headers.Add("Content-Security-Policy", "default-src 'self';");
                    context.Response.Headers.Add("X-XSS-Protection", "1; mode=block");
                    context.Response.Headers.Add("X-Content-Type-Options", "nosniff");
                    context.Response.Headers.Add("X-Frame-Options", "SAMEORIGIN");
                    await next.Invoke();
                });
                next(builder);
            };
        }
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants