What does "trust proxy" actually do in express.js, and do I need to use it?
node.jsNginxExpressProxynode.js Problem Overview
I am writing an express app that sits behind an nginx server. I was reading through express's documentation and it mentioned the 'trust proxy' setting. All it says is
>trust proxy Enables reverse proxy support, disabled by default
I read the little article here that explains Secure Sessions in Node with nginx.
<http://blog.nikmartin.com/2013/07/secure-sessions-in-nodejs-with-nginx.html>
So I am curious. Does setting 'trust proxy' to true only matter when using HTTPS? Currently my app is just HTTP between the client and nginx. If I set it to true now, are there any side-effects/repercussions I need to be aware of? Is there any point to setting it true now?
node.js Solutions
Solution 1 - node.js
This is explained in detail in the express behind the proxies guide
>By enabling the "trust proxy" setting via app.enable('trust proxy'), Express will have knowledge that it's sitting behind a proxy and that the X-Forwarded-* header fields may be trusted, which otherwise may be easily spoofed. > >Enabling this setting has several subtle effects. The first of which is that X-Forwarded-Proto may be set by the reverse proxy to tell the app that it is https or simply http. This value is reflected by req.protocol. > >The second change this makes is the req.ip and req.ips values will be populated with X-Forwarded-For's list of addresses.
Solution 2 - node.js
Annotated code to explain use of trust proxy
var express = require('express');
var app = express();
// Set the ip-address of your trusted reverse proxy server such as
// haproxy or Apache mod proxy or nginx configured as proxy or others.
// The proxy server should insert the ip address of the remote client
// through request header 'X-Forwarded-For' as
// 'X-Forwarded-For: some.client.ip.address'
// Insertion of the forward header is an option on most proxy software
app.set('trust proxy', '127.0.0.1');
app.get('/test', function(req, res){
var ip = req.ip; // trust proxy sets ip to the remote client (not to the ip of the last reverse proxy server)
if (ip.substr(0,7) == '::ffff:') { // fix for if you have both ipv4 and ipv6
ip = ip.substr(7);
}
// req.ip and req.protocol are now set to ip and protocol of the client, not the ip and protocol of the reverse proxy server
// req.headers['x-forwarded-for'] is not changed
// req.headers['x-forwarded-for'] contains more than 1 forwarder when
// there are more forwarders between the client and nodejs.
// Forwarders can also be spoofed by the client, but
// app.set('trust proxy') selects the correct client ip from the list
// if the nodejs server is called directly, bypassing the trusted proxies,
// then 'trust proxy' ignores x-forwarded-for headers and
// sets req.ip to the remote client ip address
res.json({"ip": ip, "protocol": req.protocol, "headers": req.headers['x-forwarded-for']});
});
// in this example the reverse proxy is expected to forward to port 3110
var port = 3110;
app.listen(port);
// test through proxy: http://yourproxyserver/test, req.ip should be your client ip
// test direct connection: http://yournodeserver:3110/test, req.ip should be your client ip even if you insert bogus x-forwarded-for request headers
console.log('Listening at http://localhost:' + port);
Solution 3 - node.js
TLDR : Application setting trust proxy simply intended to be used if the express application is behind a proxy. Enabling this when there's a proxy helps to resolve following properties through well known headers (mainly X-Forwarded-For, X-Forwarded-Proto)
More details
I ended up here when searching for what trust proxy really does with regards to express-session. None of the answers helped me.
Default value - false (disabled)
IMO the best documentation is at Application Settings
> trust proxy
>
> Indicates the app is behind a front-facing proxy, and to use the
> X-Forwarded-* headers to determine the connection and the IP address
> of the client. NOTE: X-Forwarded-* headers are easily spoofed and the
> detected IP addresses are unreliable.
>
> When enabled, Express attempts to determine the IP address of the
> client connected through the front-facing proxy, or series of proxies.
> The req.ips
property, then contains an array of IP addresses the
> client is connected through. To enable it, use the values described in
> the trust proxy options table.
>
> The trust proxy
setting is implemented using the proxy-addr package.
> For more information, see its documentation.
>
> NOTE: Sub-apps will inherit the value of this setting, even though it
> has a default value.
p.s - If you are trying to see how this helps with express-session, then enabling trust proxy is required to get the correct value for req.secure
Solution 4 - node.js
Since nginx
is mentioned in the question, note that in your nginx conf (e.g. /etc/nginx/sites-enabled/default) you also need to explicitly set the header variable in order to pass it through to express:
proxy_set_header X-Forwarded-For $remote_addr;
location /api/ {
proxy_pass "http://127.0.0.1:8000";
}
That's the bare minimum required, however something like this below will be faster by using zone of persistent connections to your upstream server(s):
upstream backendAPI {
zone upstreamZone 64K;
server 127.0.0.1:8000 weight=1 max_fails=2 fail_timeout=4s;
keepalive 2;
}
proxy_set_header X-Forwarded-For $remote_addr;
location /api/ {
proxy_pass http://backendAPI;
proxy_http_version 1.1;
proxy_set_header "Connection" "";
}
Then you can enable the user's (supposed) IP address in the express server's request object by switching on "trust proxy":
const app = express();
app.set("trust proxy", true); // populate req.ip
// you can also name the proxy servers ips for increased security:
// app.set("trust proxy", "127.0.0.1");
// app.set("trust proxy", "192.168.3.3");
app.get("/api/myIP", (req, res) => {
const ip = req.ip;
return res.json({ ip });
});
app.listen(8000);