Skip to content

Commit

Permalink
fix x-forwarded-header parser
Browse files Browse the repository at this point in the history
change the order of ip extraction
  • Loading branch information
aseyfpour committed Jun 28, 2022
1 parent 931a4fe commit 3d45dac
Show file tree
Hide file tree
Showing 3 changed files with 10 additions and 8 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ It looks for specific headers in the request and falls back to some defaults if
The user ip is determined by the following order:

1. `X-Client-IP`
2. `X-Forwarded-For` (Header may return multiple IP addresses in the format: "proxy 1 IP, proxy 2 IP, client IP, ", so we take the the last one.)
2. `X-Forwarded-For` (Header may return multiple IP addresses in the format: "client IP, proxy 1 IP, proxy 2 IP", so we take the first one.)
3. `CF-Connecting-IP` (Cloudflare)
4. `Fastly-Client-Ip` (Fastly CDN and Firebase hosting header when forwared to a cloud function)
5. `True-Client-Ip` (Akamai and Cloudflare)
Expand Down
6 changes: 3 additions & 3 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ function getClientIpFromXForwardedFor(value) {
}

// x-forwarded-for may return multiple IP addresses in the format:
// "proxy 1 IP, proxy 2 IP, client IP"
// "client IP, proxy 1 IP, proxy 2 IP"
// Therefore, the right-most IP address is the IP address of the most recent proxy
// and the left-most IP address is the IP address of the originating client.
// source: http://docs.aws.amazon.com/elasticloadbalancing/latest/classic/x-forwarded-headers.html
// source: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For
// Azure Web App's also adds a port for some reason, so we'll only use the first part (the IP)
const forwardedIps = value.split(',').map((e) => {
const ip = e.trim();
Expand All @@ -36,7 +36,7 @@ function getClientIpFromXForwardedFor(value) {
// Sometimes IP addresses in this header can be 'unknown' (http://stackoverflow.com/a/11285650).
// Therefore taking the right-most IP address that is not unknown
// A Squid configuration directive can also set the value to "unknown" (http://www.squid-cache.org/Doc/config/forwarded_for/)
for (let i = forwardedIps.length - 1; i >= 0; i -= 1) {
for (let i = 0; i < forwardedIps.length; i++) {
if (is.ip(forwardedIps[i])) {
return forwardedIps[i];
}
Expand Down
10 changes: 6 additions & 4 deletions test/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
const http = require('http');

const request = require('request');
const requestIp = require('../src/index.js');
const tapSpec = require('tap-spec');
const test = require('tape');

const requestIp = require('../src/index.js');

test.createStream().pipe(tapSpec()).pipe(process.stdout);

// Setup local server for testing
Expand Down Expand Up @@ -47,7 +49,7 @@ test('getClientIpFromXForwardedFor', (t) => {
t.plan(3);
t.equal(
requestIp.getClientIpFromXForwardedFor('107.77.213.113, 172.31.41.116'),
'172.31.41.116',
'107.77.213.113',
);
t.equal(requestIp.getClientIpFromXForwardedFor('unknown, unknown'), null);
t.throws(() => requestIp.getClientIpFromXForwardedFor({}), TypeError);
Expand Down Expand Up @@ -125,7 +127,7 @@ test('x-forwarded-for', (t) => {
if (!error && response.statusCode === 200) {
// make sure response ip is the same as the one we passed in
const lastIp = options.headers['x-forwarded-for']
.split(',')[2]
.split(',')[0]
.trim();
t.equal(lastIp, found);
server.close();
Expand Down Expand Up @@ -526,7 +528,7 @@ test('android request to AWS EBS app (x-forwarded-for)', (t) => {
headers: {
host: '[redacted]',
'x-real-ip': '172.31.41.116',
'x-forwarded-for': `172.31.41.116, ${wanted}`,
'x-forwarded-for': `${wanted}, 172.31.41.116`,
'accept-encoding': 'gzip',
'user-agent': 'okhttp/3.4.1',
'x-forwarded-port': '443',
Expand Down

0 comments on commit 3d45dac

Please sign in to comment.