33

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?

kspearrin
  • 463
  • 1
  • 4
  • 8

5 Answers5

38

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 a header to the 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;

Wilt
  • 773
  • 9
  • 13
  • 3
    help, proxy_hide_header works with proxy_pass, it doesn't work with 'return' – Dee Jan 24 '20 at 08:35
  • @datdinhquoc What do you mean with *"it doesn't work with 'return'"*? Could you elaborate or even better post a question and send me a link? – Wilt Jan 24 '20 at 10:31
  • i want to change a response header, but 'return' in server block will pass the url to browser and some http 302 happen in browser, i cant add the extra header to the final redirected url – Dee Jan 24 '20 at 18:20
  • 1
    This only works for response headers set by an upstream server but not for headers set by nginx self like "server" header for example. – Daniel W. Aug 03 '20 at 15:21
6

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/

Miguel Mota
  • 351
  • 3
  • 7
5

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';
    ...
}
Leo Gallego
  • 1,893
  • 9
  • 17
2

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.

Michael Hampton
  • 244,070
  • 43
  • 506
  • 972
  • 1
    Yes, I was actually doing this intentionally since I wanted them to apply to all locations without having to include it at every location. It sounds like what I am trying to do is not possible. – kspearrin Sep 02 '18 at 21:20
  • Sure it is, just follow my instructions and DO NOT put it in the `server` or in the `location` where you don't want the headers sent. – Michael Hampton Sep 02 '18 at 21:23
1

Using the Nginx Lua module.

You will need the nginx-extras package installed. For example in aptitude do a apt install nginx-extras.

In nginx.conf:

load_module /usr/lib/nginx/modules/ndk_http_module.so;
load_module /usr/lib/nginx/modules/ngx_http_lua_module.so;

http {
  ...

  header_filter_by_lua_block {
    ngx.header["server"] = nil
  }
}

To verify run a nginx -V and you will see http-lua. The ndk_http_module.so is needed to load the ngx_http_lua_module.so module.

Always best to run an nginx -t to verify your configuration, as well.