Set-Cookie Manipulation in reverse_proxy

1. My Caddy version (caddy version):

v2.0.0-rc.3

2. How I run Caddy:

I was setting up a reverse proxy for my favourite game canto.world-of-dungeons.org as some of my friends complained about the bad server connection. So I set up a simple Caddy reverse proxy on my VPS with domain name canto.wannaexpresso.com, but after I logged in I couldn’t do anything as the game alerts ‘please enable cookie’.

I thought the problem was with set-cookie after I read an article on nginx reverse proxy which suggested sending and receiving Set-Cookie with the correct domain, that is, sending original domain set-cookie to canto.world-of-dungeons.org and returning canto.wannaexpresso.com set-cookie to browser.

So I tried setting header_up in Caddyfile with replacements, but the set-cookie turned from

world=CC; expires=Sat, 01-Aug-2020 01:11:00 GMT; path=/; domain=world-of-dungeons.org

to

wannaexpresso.comwwannaexpresso.comowannaexpresso.comrwannaexpresso.comlwannaexpresso.comdwannaexpresso.com=wannaexpresso.comCwannaexpresso.comCwannaexpresso.com;wannaexpresso.com wannaexpresso.comewannaexpresso.comxwannaexpresso.compwannaexpresso.comiwannaexpresso.comrwannaexpresso.comewannaexpresso.comswannaexpresso.com=wannaexpresso.comSwannaexpresso.comawannaexpresso.comtwannaexpresso.com,wannaexpresso.com wannaexpresso.com0wannaexpresso.com1wannaexpresso.com-wannaexpresso.comAwannaexpresso.comuwannaexpresso.comgwannaexpresso.com-wannaexpresso.com2wannaexpresso.com0wannaexpresso.com2wannaexpresso.com0wannaexpresso.com wannaexpresso.com0wannaexpresso.com1wannaexpresso.com:wannaexpresso.com1wannaexpresso.com1wannaexpresso.com:wannaexpresso.com0wannaexpresso.com0wannaexpresso.com wannaexpresso.comGwannaexpresso.comMwannaexpresso.comTwannaexpresso.com;wannaexpresso.com wannaexpresso.compwannaexpresso.comawannaexpresso.comtwannaexpresso.comhwannaexpresso.com=wannaexpresso.com/wannaexpresso.com;wannaexpresso.com wannaexpresso.comdwannaexpresso.comowannaexpresso.commwannaexpresso.comawannaexpresso.comiwannaexpresso.comnwannaexpresso.com=wannaexpresso.comwwannaexpresso.comowannaexpresso.comrwannaexpresso.comlwannaexpresso.comdwannaexpresso.com-wannaexpresso.comowannaexpresso.comfwannaexpresso.com-wannaexpresso.comdwannaexpresso.comuwannaexpresso.comnwannaexpresso.comgwannaexpresso.comewannaexpresso.comowannaexpresso.comnwannaexpresso.comswannaexpresso.com.wannaexpresso.comowannaexpresso.comrwannaexpresso.comgwannaexpresso.com

I think I probably need a fix on the replacement statements. Please help me orz…

a. System environment:

Debian 10

b. Command:

caddy run

c. My complete Caddyfile or JSON config:

# My Caddyfile
canto.wannaexpresso.com {
  encode gzip
  reverse_proxy * http://canto.world-of-dungeons.org {
    header_up Host canto.world-of-dungeons.org
    header_up Set-Cookie wannaexpresso.com world-of-dungeons.org
    header_down Set-Cookie world-of-dungeons.org wannaexpresso.com
  }
}

Haha, woooahh nellie. Lemme take a look at that. I’ll get back to you.

Edit: Yep, I can reproduce it:

curl -v "http://localhost:1111"
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 1111 (#0)
> GET / HTTP/1.1
> Host: localhost:1111
> User-Agent: curl/7.64.1
> Accept: */*
> 
< HTTP/1.1 200 OK
< Content-Length: 21
< Date: Thu, 23 Apr 2020 01:40:48 GMT
< Server: Caddy
< Server: Caddy
< Set-Cookie: wannaexpresso.comwwannaexpresso.comowannaexpresso.comrwannaexpresso.comlwannaexpresso.comdwannaexpresso.com=wannaexpresso.comCwannaexpresso.comCwannaexpresso.com;wannaexpresso.com wannaexpresso.comewannaexpresso.comxwannaexpresso.compwannaexpresso.comiwannaexpresso.comrwannaexpresso.comewannaexpresso.comswannaexpresso.com=wannaexpresso.comSwannaexpresso.comawannaexpresso.comtwannaexpresso.com,wannaexpresso.com wannaexpresso.com0wannaexpresso.com1wannaexpresso.com-wannaexpresso.comAwannaexpresso.comuwannaexpresso.comgwannaexpresso.com-wannaexpresso.com2wannaexpresso.com0wannaexpresso.com2wannaexpresso.com0wannaexpresso.com wannaexpresso.com0wannaexpresso.com1wannaexpresso.com:wannaexpresso.com1wannaexpresso.com1wannaexpresso.com:wannaexpresso.com0wannaexpresso.com0wannaexpresso.com wannaexpresso.comGwannaexpresso.comMwannaexpresso.comTwannaexpresso.com;wannaexpresso.com wannaexpresso.compwannaexpresso.comawannaexpresso.comtwannaexpresso.comhwannaexpresso.com=wannaexpresso.com/wannaexpresso.com;wannaexpresso.com wannaexpresso.comdwannaexpresso.comowannaexpresso.commwannaexpresso.comawannaexpresso.comiwannaexpresso.comnwannaexpresso.com=wannaexpresso.comwwannaexpresso.comowannaexpresso.comrwannaexpresso.comlwannaexpresso.comdwannaexpresso.com-wannaexpresso.comowannaexpresso.comfwannaexpresso.com-wannaexpresso.comdwannaexpresso.comuwannaexpresso.comnwannaexpresso.comgwannaexpresso.comewannaexpresso.comowannaexpresso.comnwannaexpresso.comswannaexpresso.com.wannaexpresso.comowannaexpresso.comrwannaexpresso.comgwannaexpresso.com
< Content-Type: text/plain; charset=utf-8

Fun

Ha! I know you’ve been checking on me! Thanks matt!

Update: It works properly if you use header Set-Cookie world-of-dungeons.org wannaexpresso.com outside of your reverse_proxy directive. This should be pretty easy to fix, I think…

Alrighty, fixed in reverseproxy: Don't forget to provision embedded headers handler · caddyserver/caddy@1b06181 · GitHub. Could you try that out, @Peter_Zhang? (Build artifacts will be available at that commit shortly.)

I’m still getting bad cookies with header Set-Cookie.

canto.wannaexpresso.com {
  encode gzip
  header Set-Cookie world-of-dungeons.org wannaexpresso.com
  reverse_proxy * http://canto.world-of-dungeons.org {
    header_up Host canto.world-of-dungeons.org
  }
}

And do you mean I could build on your latest commit to get it fixed? Thankkks a lot matt!

Can you elaborate?

Yes - the CI server compiles Caddy for you at each commit so you could just download that if you want.

On the page right after I login (which is / I believe), the original site headers are like

Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Connection: Keep-Alive
Content-Encoding: gzip
Content-Type: text/html
Date: Thu, 23 Apr 2020 02:08:12 GMT
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Keep-Alive: timeout=5, max=200
Pragma: no-cache
Server: Apache/2.2.22 (Debian)
Set-Cookie: world=CC; expires=Sat, 01-Aug-2020 02:08:12 GMT; path=/; domain=world-of-dungeons.org
Set-Cookie: plain=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=world-of-dungeons.org
Set-Cookie: warn_email=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=world-of-dungeons.org
Transfer-Encoding: chunked
Vary: Accept-Encoding
X-DNS-Prefetch-Control: off
X-Powered-By: PHP/5.4.45-0+deb7u14
X-XSS-Protection: 0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-GB;q=0.8,en;q=0.7
Connection: keep-alive
Cookie: savepass=1; system=a5HJ4gkO0SH4xFmuSxsWH8PTeQ5xXfWx; world=CC; 42834fb68c786f736988cc445ffdc7ba=255c595bc5b02c7295975064fe2e3c8f; login_CC=gsr9l8l7t68nlggog94qo948bcvzlw02; PHPSESSID=bc56u3yqc6oc01efq317c2je9vx72wl7
DNT: 1
Host: canto.world-of-dungeons.org
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36

And on my proxy site it looks like this

cache-control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
content-encoding: gzip
content-type: text/html
date: Thu, 23 Apr 2020 02:08:31 GMT
expires: Thu, 19 Nov 1981 08:52:00 GMT
pragma: no-cache
server: Caddy
server: Apache/2.2.22 (Debian)
set-cookie: world=CC; expires=Sat, 01-Aug-2020 02:08:31 GMT; path=/; domain=world-of-dungeons.org
set-cookie: plain=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=world-of-dungeons.org
set-cookie: savepass=1; expires=Wed, 22-Jul-2020 02:08:31 GMT; path=/; domain=world-of-dungeons.org
set-cookie: PHPSESSID=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/
set-cookie: warn_email=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=world-of-dungeons.org
set-cookie: system=Osz4IjRpwIsppReJTkG1dynIHsWWuIR6; expires=Wed, 22-Jul-2020 02:08:31 GMT; path=/; domain=world-of-dungeons.org
set-cookie: a0adc13c13ed6ad66308b620adb64275=255c595bc5b02c7295975064fe2e3c8f; expires=Thu, 23-Apr-2020 03:08:31 GMT; path=/; domain=world-of-dungeons.org
set-cookie: login_CC=9invao8byjhrz0ui3iq8gjsmaaukq7fz; expires=Wed, 22-Jul-2020 02:08:31 GMT; path=/; domain=world-of-dungeons.org
set-cookie: world=CC; expires=Wed, 22-Jul-2020 02:08:31 GMT; path=/; domain=world-of-dungeons.org
status: 200
vary: Accept-Encoding
X-DNS-Prefetch-Control: off
x-powered-by: PHP/5.4.45-0+deb7u14
x-xss-protection: 0
:authority: canto.wannaexpresso.com
:method: POST
:path: /
:scheme: https
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
accept-encoding: gzip, deflate, br
accept-language: zh-CN,zh;q=0.9,en-GB;q=0.8,en;q=0.7
cache-control: max-age=0
content-length: 95
content-type: application/x-www-form-urlencoded
cookie: PHPSESSID=ixqns55rbcp5mg7z2lztrfciak0dtvg7
dnt: 1
origin: https://canto.wannaexpresso.com
referer: https://canto.wannaexpresso.com/
sec-fetch-dest: document
sec-fetch-mode: navigate
sec-fetch-site: same-origin
sec-fetch-user: ?1
upgrade-insecure-requests: 1
user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36

And after I login onto my proxy site, any further operation would lead to a game error page warning “browser does not support cookie or cookie disabled”.

When I click into the same link on both sites after login , I checked again the headers, it seemed that some of the cookies are missing:

The original site header contains

# Correct Page on Original Site
Cookie: savepass=1; system=a5HJ4gkO0SH4xFmuSxsWH8PTeQ5xXfWx; world=CC; 42834fb68c786f736988cc445ffdc7ba=255c595bc5b02c7295975064fe2e3c8f; login_CC=gsr9l8l7t68nlggog94qo948bcvzlw02; PHPSESSID=bc56u3yqc6oc01efq317c2je9vx72wl7

But my proxy site cookie only had

# Error Page on Proxy Site
Cookie: PHPSESSID=nfq7gj0j560a0zzlei3zhkp5yquhve73

Is that using the latest patch from a few minutes ago, with your original Caddyfile? (i.e. header_down not header directive)?

That’s with original caddy rc2 and header set-cookie

Okay – that’s an old version, and is broken. Run from the latest commit on master, and use your original Caddyfile and see how it goes.

Got it, working on building!

You can grab the CI artifacts from here if you want to avoid building

OMG that’s even more awesome! Wish I had known that!

My VPS couldn’t build because of the 512M memory so I built on my laptop and uploaded.

And it worked! Now the set-cookies are correctly set to domain=wannaexpresso.com.

I’m using caddy version (devel) and Caddyfile as follows:

canto.wannaexpresso.com {
  encode gzip
  reverse_proxy * http://canto.world-of-dungeons.org {
    header_up Host canto.world-of-dungeons.org
    header_down Set-Cookie world-of-dungeons.org wannaexpresso.com
  }
}

Thanks heavenly matt!

Great, glad to hear it!