Hapi: remote address is blank when behind a proxy (named pipes)

Created on 12 Dec 2013  路  8Comments  路  Source: hapijs/hapi

When a hapi app is running behind a proxy, the address of the client isn鈥檛 visible to the app or in good logs. In our case, when running behind iisnode this information is provided by the proxy in the x-forwarded-for header. I don鈥檛 have other systems available to test with, but XFF appears to be the standard for a number of load balancers and platforms (http://en.wikipedia.org/wiki/X-Forwarded-For).

At present we鈥檙e working around this by replacing the blank remoteAddress we get, with the header value prior to sending the information off to our logging provider.

This could be resolved for named pipe proxies where req.connection.remoteAddress is undefined by updating /lib/request.js to:

remoteAddress: (req.connection && req.connection.remoteAddress) || req.headers['x-forwarded-for'] || ''

however this doesn鈥檛 address the case where the front proxy is making an IP connection to hapi/node. In that case I suspect hapi would also log the address of the proxy, not of the actual client, but you wouldn't want to do the following to support IP based proxies as that it would enable a client to lie.

req.headers['x-forwarded-for'] || (req.connection && req.connection.remoteAddress) || ''

It may make more sense to expose a server configuration setting to take remote address from a proxy specified header only for those that need it. Any thoughts? I鈥檇 be happy to implement that (or any desired approach) and pull request.

feature

Most helpful comment

You may not want the first in the list @jasonswearingen. Each proxy the request passes through appends what it sees as the client ip address to x-forwarded-for. Trusting the first entry in the list means that the original requestor can spoof an x-forwarded-for and you'd use whatever it sent. Topologies may differ but in our case we have a single proxy in front of node/hapi -- so we always take the last entry.

All 8 comments

So remoteAddress is a very specific thing, which is exactly that - the IP address of the direct client connection. It doesn't matter if it is a proxy or the remote client all the way. XFF can be nested multiple tiers (a list). I am open to offering a new info field on the request but need to see what the implementation looks like first.

Feel free to outline a solution and I'll review.

Thanks!

This may be the best option then - it only supports proxies running on the same box that use named pipes as in this case remoteAddress is undefined. There's no ambiguity to XFF in this case.

remoteAddress: (req.connection && req.connection.remoteAddress) || req.headers['x-forwarded-for'] || ''

That's too narrow to support as part of the core.

Feels like it, and I'll bet we'll find a few other environment (windows azure+iis+iisnode) specific needs that belong in a plugin. We'll put that out once we get our hapi apps to prod.

Thanks

fyi, if anyone uses the solution @spanditcaa mentions above, keep in mind that x-forward-for can contain multiple addresses, so you need to split by comma and take the first, as in:

/**
 *  extract the final client ip address.   can not use request.info.remoteAddress directly because client may be behind a proxy/loadbalancer
 * @param request
 */
export function extractClientIp(request: hapi.Request) {
    //from http://stackoverflow.com/questions/29496257/knowing-request-ip-in-hapi-js-restful-api
    var xFF = request.headers['x-forwarded-for'];
    var ip = xFF ? xFF.split(',')[0] : request.info.remoteAddress;
    return ip;
}

You may not want the first in the list @jasonswearingen. Each proxy the request passes through appends what it sees as the client ip address to x-forwarded-for. Trusting the first entry in the list means that the original requestor can spoof an x-forwarded-for and you'd use whatever it sent. Topologies may differ but in our case we have a single proxy in front of node/hapi -- so we always take the last entry.

Thanks for those details! Yes in my environment I have 2 steps in front, so I better change my code accordingly.

Thank you!

This thread has been automatically locked due to inactivity. Please open a new issue for related bugs or questions following the new issue template instructions.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

hueniverse picture hueniverse  路  4Comments

taoeffect picture taoeffect  路  3Comments

arb picture arb  路  4Comments

foobar1123 picture foobar1123  路  3Comments

hovmand picture hovmand  路  3Comments