What does "trust proxy" actually do in express.js, and do I need to use it?

node.jsNginxExpressProxy

node.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);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionjoeycozzaView Question on Stackoverflow
Solution 1 - node.jsAkshat Jiwan SharmaView Answer on Stackoverflow
Solution 2 - node.jsannebView Answer on Stackoverflow
Solution 3 - node.jsKavindu DodanduwaView Answer on Stackoverflow
Solution 4 - node.jsJeremy JonesView Answer on Stackoverflow