How do I remove a server-added header from proxied location?

I have an Nginx proxy setup where I add several security-related headers to the server so that they return on all proxy locations. On some locations I need to add additional headers (ex. Content-Security-Policy to /), while on other specific locations I need to remove one of the headers (ex. X-Frame-Options from /framepage.html) added at the server level.

nginx.conf

# ...

server {
  # ...

  include security-headers.conf;

  location / {
    proxy_pass http://web:5000/;
    include security-headers.conf;
    add_header Content-Security-Policy "my csp...";
  }

  location = /framepage.html {
    proxy_pass http://web:5000/framepage.html;
    # TODO: remove `X-Frame-Options` response header from this specific page
    # Tried add_header X-Frame-Options "";
    # Tried proxy_set_header X-Frame-Options "";
    # Tried proxy_hide_header X-Frame-Options;
  }

  location /api/ {
    proxy_pass http://api:5000/;
  }

  location /otherstuff/ {
    proxy_pass http://otherstuff:5000/;
  }

  # ...
}

security-headers.conf

add_header Referrer-Policy same-origin;
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";

I have tried the following, but none of them seem to remove the X-Frame-Options header from the /framepage.html location response:

  • add_header X-Frame-Options "";
  • proxy_set_header X-Frame-Options "";
  • proxy_hide_header X-Frame-Options;

How can I remove the X-Frame-Options header from the /framepage.html location response?


Solution 1:

The header config attributes are a bit confusing, this is what they do:

proxy_set_header is to set a request header
add_header is to add header to response
proxy_hide_header is to hide a response header

If you want to replace a header that already exists in the response it is not enough with add_header because it will stack the values (from server and the one you added).

You have to do this in two steps:

1) remove header:
proxy_hide_header Access-Control-Allow-Origin;

2) add your custom header value:
add_header Access-Control-Allow-Origin "*" always;

Solution 2:

You can use the headers_more module. Example:

location / {
    proxy_pass http://upstream_server/;
    more_clear_headers 'Access-Control-Allow-Origin';
}

https://www.nginx.com/resources/wiki/modules/headers_more/

Solution 3:

You could probably try to use the 3rd party "Headers More" module:

https://github.com/openresty/headers-more-nginx-module

And something along the lines of:

load_module modules/ngx_http_headers_more_filter_module.so;

http {
    ...
    more_clear_headers 'X-Frame-Options';
    ...
}

Solution 4:

Don't include security-headers.conf at the server level. Only include it in each individual location where you want these headers to be sent.

The reason for this is that add_header directives are inherited from the previous level if and only if the current level has no add_header directives. Thus, your including them in the server block causes them to be included in every location as you aren't overriding them in any location.