3 ms·
This is a good point. I should have known better, but I just checked a setup I made a while back (nginx "proxy_set_header" [1] + Rust http::HeaderMap::get [2]),
by scottlamb 5y ago
This is a good point. I should have known better, but I just checked a setup I made a while back (nginx "proxy_set_header" [1] + Rust http::HeaderMap::get [2]), and I was doing it wrong. The nginx command appends, and get returns the first. Oops. At least I'm not doing IP-based auth, but I am looking for this to detect if the client is using TLS (up to the reverse proxy server, the backhaul is plaintext right now, like [3]) as well as logging the IP.
Another problem that I suspect is common: connections that sometimes go through a reverse proxy, sometimes not. In my setup, the "not" ones in theory are trusted (on the LAN or localhost) but still it doesn't feel right to not really know if the header came from the proxy or not. I could add a shared secret or something to the header, but given that a LAN-based attacker could sniff everything (not just this but also the actual user credentials/traffic) via ARP spoofing or something, it probably doesn't as much sense to bother before getting rid of the plaintext backhaul.
Speaking of which, it'd be nice to make the TLS end-to-end: from the user through a proxy that doesn't decrypt all the way to the application server. But I'm not sure what the state of the art there is. It used to be possible to dispatch based on the SNI traffic and then proxy at the TCP level, but I know TLS 1.3 added encrypted SNI. Not sure if the proxy can force clients fall back to non-encrypted SNI. I could imagine the spec authors making a point of not allowing this so a man-in-the-middle can't find the intended host. Maybe the two legs just have to be encrypted separately now.
[1] http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_set_header http://nginx.org/en/docs/http/ngx_http_proxy_module.html#pro...
[2] https://docs.rs/http/0.2.6/http/header/struct.HeaderMap.html#method.get https://docs.rs/http/0.2.6/http/header/struct.HeaderMap.html...
[3] https://blog.encrypt.me/2013/11/05/ssl-added-and-removed-here-nsa-smiley/ https://blog.encrypt.me/2013/11/05/ssl-added-and-removed-her...
- toast0 5y ago> I know TLS 1.3 added encrypted SNI. Not sure if the proxy can force clients fall back to non-encrypted SNI. Encrypted SNI is not the default. You've got to do a fair bit of work to do it. You'd probably want your proxy to be able to decode it to direct the traffic anyway.
- anderspitman 5y ago> Speaking of which, it'd be nice to make the TLS end-to-end: from the user through a proxy that doesn't decrypt all the way to the application server. But I'm not sure what the state of the art there is. It used to be possible to dispatch based on the SNI traffic and then proxy at the TCP level, but I know TLS 1.3 added encrypted SNI. Not sure if the proxy can force clients fall back to non-encrypted SNI. I could imagine the spec authors making a point of not allowing this so a man-in-the-middle can't find the intended host. Maybe the two legs just have to be encrypted separately now. My boringproxy[0] project has a mode for doing SNI routing at the reverse proxy, and tunneling it all the way back to a local client machine which handles the actual TLS termination. The client also gets certs automatically from Let's Encrypt. So you end up with automated end-to-end encryption where the boringproxy server/VPS can't decrypt any of the traffic. Early versions of boringproxy acted as a more traditional reverse proxy, terminating the TLS at the server then making a new HTTP request upstream. Eventually I added the ability to move the HTTP proxy into the client to enable e2ee. Most recently I implemented raw TLS all the way. There are tradeoffs: Pros: * End-to-end encryption. * Simplicity. You just need to peek at the SNI and look up what TCP tunnel to pipe into. * Things like WebSockets and other hop-by-hop requests don't need to be implemented by the proxy. Cons: * You lose the ability to do compression/caching/CDN/etc at the server. * You can't support new protocols like HTTP/2, HTTP/3, etc at your server because it only understands TCP wrapped in TLS. In practice, I think these tradeoffs are totally worth it for self-hosting. I've found performance to be great for my purposes. As for encrypted SNI (ESNI, now wrapped into encrypted client hello, ECH), I'm pretty sure it will be implemented in a tiered approach like you surmise. So in my case the boringproxy server will have the keys to decrypt the client hello, but the origin servers will still control the actual TLS decryption. [0]: https://boringproxy.io https://boringproxy.io
- remram 5y agoI have just checked and the nginx directive "proxy_set_header" does NOT append a value, it replaces. It will only be added to the existing value if you set it to `$proxy_add_x_forwarded_for` instead of `$remote_addr`.