Search code examples
nginxcookiescross-domainsubdomainreverse-proxy

Nginx proxy_cookie_header not working (domain<-> sub domain)


i'm exhausted about this issue.. for 2days... I believe that there are someone who can catch the bug..
Nowadays i'm make a website. it totally ok in local system.. but this error happend. when release by nginx reverse proxy.

[enviorment]
Frontend - Next.js (owl-dev.me)
Backend - .Net Core (backend.owl.dev.me)
Nginx - 1.18.0

[issue]
I got a Cookie from Backend after login. but the cookie's domain is not owl-dev.me but backend.owl.dev.me. so can't save and get cookie in ssr (* if i change the domain name manually in browser it work fine) enter image description here

[what i tried]
i found that nginx can change cookie domain by nginx. proxy_cookie_domain but it didn't work.
some article say that can work by Regular expression but didn't work.
how i can fix this? what's the matter??!!?

[Nginx setting]

server {
    # SSL configuration
    #
    listen 443 ssl http2 default_server;
    listen [::]:443 ssl http2 default_server;
    client_max_body_size 10M;

    ssl_certificate "/etc/letsencrypt/live/www.owl-dev.me/fullchain.pem";
    ssl_certificate_key "/etc/letsencrypt/live/www.owl-dev.me/privkey.pem";
    ssl_dhparam "/etc/nginx/ssl/dhparams.pem";

    add_header Strict-Transport-Security "max-age=31536000";

    # Add index.php to the list if you are using PHP

    server_name owl.dev.me  www.owl-dev.me;

    location / {
        proxy_set_header Host $host;
        proxy_pass http://localhost:3000;
    }   
}

server {
    # SSL configuration
    #
    listen 443 ssl http2;
    listen [::]:443 ssl http2 ;
    client_max_body_size 10M;

    ssl_certificate "/etc/letsencrypt/live/backend.owl-dev.me/fullchain.pem";
    ssl_certificate_key "/etc/letsencrypt/live/backend.owl-dev.me/privkey.pem";
    ssl_dhparam "/etc/nginx/ssl/dhparams.pem";

    server_name backend.owl-dev.me;

    location / {
        proxy_cookie_domain ~^(.*)$ "$1; Domain=backend.owl-dev.me";
        proxy_set_header Host www.owl-dev.me;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header X-Real-IP $remote_addr;
        proxy_pass https://localhost:5001;
    }
}

Solution

  • The first and the most important thing is that the proxy_cookie_domain directive is intended only to change the domain attribute of the cookies coming from the upstream. That is, if such a cookie won't contain the domain attribute, proxy_cookie_domain directive will be completely useless and such a cookie will be tied to the domain it comes from.

    The second, looks like my knowledge on the subject was somehow outdated and the specs get changed during the last years. The leading dot character is outdated and the cookie that is set to some domain will be available to all its subdomains anyway. Here is what the RFC 6265 says as of now:

    The Domain attribute specifies those hosts to which the cookie will be sent. For example, if the value of the Domain attribute is "example.com", the user agent will include the cookie in the Cookie header when making HTTP requests to example.com, www.example.com, and www.corp.example.com. (Note that a leading %x2E ("."), if present, is ignored even though that character is not permitted, but a trailing %x2E ("."), if present, will cause the user agent to ignore the attribute.) If the server omits the Domain attribute, the user agent will return the cookie only to the origin server.

    The user agent will reject cookies unless the Domain attribute specifies a scope for the cookie that would include the origin server. For example, the user agent will accept a cookie with a Domain attribute of "example.com" or of "foo.example.com" from foo.example.com, but the user agent will not accept a cookie with a Domain attribute of "bar.example.com" or of "baz.foo.example.com".

    To me, it sounds like you can't set your cookie domain attribute to www.owl-dev.me if such a cookie comes from the backend.owl-dev.me domain, but setting domain attribute to owl-dev.me (which will made the cookie available to the owl-dev.me domain and any its subdomain) should be ok.

    Summarizing all the above, to change the domain attribute to owl-dev.me no matter what value it is set to in the upstream response, you can use the following directive:

    proxy_cookie_redirect ~^ owl-dev.me;
    

    (where ~^ is a regex pattern that matches any string). However if the cookie from the upstream won't have the domain attribute at all, the directive will have no effect.