16

I have a nginx as reverse proxy that proxies my requests to different destinations. Client send different to nginx. I want to remove a specific cookie for one of my locations. For example if client send cookie A and B, I want to sent A form for /api.

How can I do that?

7
  • I'm not sure if it would work, but you can try set $cookie_A "" in the specific location. Commented May 15, 2021 at 20:42
  • can you explain more? Commented May 16, 2021 at 4:31
  • I didn't work for me Commented May 16, 2021 at 4:52
  • Do you mean that if the client send HTTP header like Cookie: A=value1; B=value2; C=value3 with some request like /api/some/command, you need to transform that header to Cookie: A=value1; C=value3? Can you add the location /api { ... } block from your nginx config to your question? Commented May 19, 2021 at 16:02
  • I didn't get what you mean. Commented May 19, 2021 at 17:35

3 Answers 3

32
+50

Assuming you are using proxy_pass directive and your cookie name is my_cookie, you can cut this cookie and its value from Cookie HTTP header this way:

location /api {

    # save original "Cookie" header value
    set $altered_cookie $http_cookie;

    # check if the "my_cookie" cookie is present
    if ($http_cookie ~ '(.*)(^|;\s)my_cookie=("[^"]*"|[^\s]*[^;]?)(\2|$|;$)(?:;\s)?(.*)') {
        # cut "my_cookie" cookie from the string
        set $altered_cookie $1$4$5;
    }

    # hide original "Cookie" header
    proxy_hide_header Cookie;

    # set "Cookie" header to the new value
    proxy_set_header  Cookie $altered_cookie;

    ... # other proxy settings here

    proxy_pass <upstream>; # change to your upstream server
}

This complex regex allows to check if the my_cookie cookie is present no matter it is at the beginning, at the middle or at the end of Cookie header value. Here are several examples showing how this regex works on different strings:

Whole "Cookie" string                                          $1                      $2      $3            $4      $5                       $1$4$5
-----------------------------------------------------------    --------------------    ----    ----------    ----    ---------------------    -----------------------------------------
"some_cookie=value1; my_cookie=value2; other_cookie=value3"    "some_cookie=value1"    "; "    "value2"      "; "    "other_cookie=value3"    "some_cookie=value1; other_cookie=value3"
"some_cookie=value1; my_cookie=value2"                         "some_cookie=value1"    "; "    "value2"      ""      ""                       "some_cookie=value1"
"my_cookie=value2; other_cookie=value3"                        ""                      ""      "value2; "    ""      "other_cookie=value3"    "other_cookie=value3"
"my_cookie=value2"                                             ""                      ""      "value2"      ""      ""                       ""

For those who are looking for the same recipe but use fastcgi_pass instead of proxy_pass - use fastcgi_param HTTP_COOKIE $altered_cookie if_not_empty; instead of proxy_hide_header and proxy_set_header directives.

Sign up to request clarification or add additional context in comments.

2 Comments

brilliant answer! Thanks! Maybe you can tell how to filter serveral cookies at once, or filter cookies like HttpOnly?
@AlexR. Considering those cookies could be placed in Cookie header in an unpredictable order, the most simple would be to use several if blocks, I think. Replace if ($http_cookie ~ ... with if ($altered_cookie ~ ... and remove those cookies one by one. Removing cookies considering their attributes like HttpOnly will require a completely different approach. A much more advanced filtering can be implemented using some scripting via lua-nginx-module, njs, etc.
1

I would recommend using the map syntax instead of if (if is evil). Also, it looks to me as if you could also leave out the non-capturing group (?:;\s)?. Therefore I have implemented this as follows:

map $http_cookie $altered_cookie {
    "~(.*)(^|;\s)my_cookie=(\"[^\"]*\"|[^\s]*[^;]?)(\2|$|;$)(.*)" $1$4$5;
    default $http_cookie;
}

3 Comments

Manuel, this does not provide an answer to the question. You can search for similar questions, or refer to the related and linked questions on the right-hand side of the page to find an answer. If you have a related but different question, ask a new question, and include a link to this one to help provide context. See: Ask questions, get answers, no distractions
Using a map is the right way to do it and avoids the if and its context shift. The map needs to go in the http context and you'd remove the set $altered_cookie... and if(...) parts of Ivan's example.
@Manuel where does this changes need to be done, we have similar problem but in our case we hav Kubernetes setup. We are really consfused on implementation part.
0

If you can recompile nginx, you might consider using the module I developed.

https://github.com/HanadaLee/ngx_http_request_cookies_filter_module

location /api {
    clear_request_cookie B;
    proxy_set_header $filtered_request_cookies;
    proxy_pass <upstream>;
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.