2

I have an upstream server that often sets Cookie(s) by returning the "Set-Cookie" response header.

I would like to have an nginx proxy in front of said upstream server:

Browser => Nginx => Upstream

If the Browser => Nginx request had the header X-No-Cookies: true I'd like the response from Upstream => Nginx => Browser not to contain the Set-Cookie response header. If X-No-Cookies had any other value, I'd lie the Set-Cookie response header to be returned unaltered. I'm not able to change the response header behavior of the upstream server.

Currently my nginx config is as follows, pay specific attention to the use of the proxy_hide_header directive. I've also echoed the $proxy_hide_header variable in the X-No-Cookies response header.

map $http_x_no_cookies $proxy_hide_header {
  default "";
  "true"  "Set-Cookie";
}

# Homepage
server {
  listen 80;
  server_name example.com;

  location /api {
    proxy_pass        https://example.com/api;
    proxy_hide_header $proxy_hide_header;
    add_header        "X-No-Cookies" $proxy_hide_header;
  }
}

When I make a request with cURL:

curl \
  http://example.com/api \
  -H 'X-No-Cookies: true' \
  -I

I get the following response headers:

Server: nginx/1.12.2
Date: Thu, 13 Dec 2018 02:26:41 GMT
Content-Type: application/json
Content-Length: 2255
Connection: keep-alive
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Accept,Authorization
Access-Control-Allow-Methods: GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS
Access-Control-Expose-Headers: Content-Length
Set-Cookie: foo=bar; Max-Age=2592000; Expires=Sat, 12 Jan 2019 02:26:41 GMT; Path=/; Domain=example.com; Secure
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-No-Cookies: Set-Cookie

Whenever the proxy_hide_header is provided an nginx variable as an argument it seems to have no effect. If I swap the variable for a string ($proxy_hide_header substituted for "Set-Cookie") I get the desired behaviour - the Set-Cookie response header is omitted.

Edit: I've pushed the code for this question to GitHub

  • My original (non-working) implementation is here
  • Ivan Shatsky's solution is here
aren55555
  • 1,677
  • 1
  • 20
  • 34

1 Answers1

6

What an interesting challenge! Truly, $proxy_hide_header does not accept variables as its parameter and cannot be used inside an if blocks. Also we cannot use $upstream_... variables directly inside a location block because its values are not evaluated yet. Finally I found a solution. We always hide Set-Cookie header and then set it again if needed, values calculating through map expressions:

map $http_x_no_cookies $hide_cookies {
    default "0";
    "true"  "1";
}

map $hide_cookies$upstream_http_set_cookie $cookies {
    ~^0(.*)$ $1;
}

upstream backend {
    server example.com;
}

server {
    listen 80;
    server_name example.com;

    location /api {
        proxy_pass        https://backend/api;
        proxy_hide_header Set-Cookie;
        add_header Set-Cookie $cookies;
    }
}
Ivan Shatsky
  • 13,267
  • 2
  • 21
  • 37
  • How did you know proxy_hide_header does not accept variables as its parameter? I was reading this doc (http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_hide_header) and couldn't find that info. – aren55555 Dec 14 '18 at 00:24
  • 1
    I think this can be called an experience :) Unless the nginx documentation on some directive explicitly states that variables may be used as its parameters, usually it means that they cannot. This is nginx way of documenting directives. – Ivan Shatsky Dec 17 '18 at 17:41
  • @Ivan Do you think there is a solution for multiple cookies? this solution will only work for one cookie. I'm working on it here: https://stackoverflow.com/questions/46470330/removing-header-from-cached-response-with-nginx/59383747 – Vixxs Dec 18 '19 at 00:40
  • @Vixxs Working with headers is tricky, I think if I faced such problem I would try to solve it with OpenResty. It is an nginx fork with embedded Lua scripting. Look at [this](https://stackoverflow.com/questions/44016867/how-come-i-cannot-set-multiple-cookies) question to see some examples. – Ivan Shatsky Dec 18 '19 at 08:14
  • @Ivan Hi I did it with a little bit of Lua in the same Nginx install, I'm a newbie at this, could you check my solution, do you think its solid?: https://stackoverflow.com/questions/46470330/removing-header-from-cached-response-with-nginx/59383747#59383747 – Vixxs Dec 19 '19 at 00:32