Overwrite specific header only

I have couple of services that require different Content-Security-Policy header. My initial attempt was to create a default middleware that will handle all common headers, and then I can create new middlewares with unique contentSecurityPolicy settings for each of the routers.

I was surprised when it turned out that if you have multiple middlewares with headers, the last one overwrites the previous. This means I have to recreate all the headers in each middleware for them to work as expected. And if I make changes in the future, I would have to make sure this is reflected in all of them.

As a workaround I tried to add customResponseHeaders with Content-Security-Policy header, but this did not overwrote the default header, even though it showed in the dashboard.

Is this the expected behavior? Does it make sense to open GitHub issue for this to be changed?

Here is an example config:

...
[http.routers.service]
  rule = "Host(`example.com`)"
  entrypoints = ["https"]
  middlewares = ["default", "service"]
  service = "service"
...
[http.middlewares.default.headers]
  accessControlAllowOrigin = "origin-list-or-null"
  stsSeconds = 315360000
  stsIncludeSubdomains = true
  stsPreload = true
  customFrameOptionsValue = "SAMEORIGIN"
  contentTypeNosniff = true
  browserXssFilter = true
  referrerPolicy = "strict-origin"
  contentSecurityPolicy = "default-src 'none'"
  featurePolicy = "notifications 'none'; camera 'none'"
[http.middlewares.service.headers]
  contentSecurityPolicy = "default-src 'none';script-src 'self' 'unsafe-inline' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src data: 'self';connect-src 'self';font-src 'self';worker-src blob:"

If you talk about the security headers not the custom ones, yes, it seems how the library has been written.

I personally would like to know what is the benefit for the user on splitting all the headers on "Custom" and "Security" and processing them differently. To me it makes things awkward as demonstrated in the OP. And if you think about interaction between custom and security headers - don't even go there...

Not sure if your second paragraph is pointed at me or the developers, but now that you explained it like this, I can say that the documentation does not help make this distinction.

Also I tried a new approach - I've set all my setting using only customResponseHeaders settings and skipping all the predefined security headers.

I then setup only a custom Content-Security-Policy for each of the services in a separate middleware and applied them as middlewares = ["service", "default"]. This gave me the output I wanted, and i was able to go from 60 down to 20 lines.

One side effect, is that in the dashboard, when you look at middlewares, you see all the custom headers bunched up on the top, and all the individual ones below them show default values that are not the correct ones.

1 Like

My second paragraph was pointed at the developers.

I have not tried that, but another possible solution is to NOT use secure part of headers. If you specify none of the secure options and put all these headers into custom headers in theory you should be able to chain them.

1 Like

This was actually what I found as a solution - entirely skipping the secure section and only using customResponseHeaders. With the side effect of not being able to easily see their settings in the Dashboard. but I can live with that trade off.

1 Like

am using 2.0.5 and it is not working

spec:
  headers:
    customResponseHeaders:
      server: ""

spec:
  headers:
    customRequestHeaders:
      Connection: "Upgrade"
      Upgrade: "websocket"
    customResponseHeaders:
      Sec-WebSocket-Protocol: http

I want to remove the server header but somehow it is not working. that middleware seems to be overwritten

I was able to set the server name to empty in my test using two separate customResponseHeaders. It seems you're uisng the same name for the two middlewares - spec. Can you change it and then update the router with the new names?