@fullerstack/nax-ipware
v0.10.0
Published
A node library for server applications retrieving user's real IP address
Downloads
59,598
Maintainers
Readme
NAX IPware (A Node Application Agnostic Library)
A node library for server applications retrieving user's real IP address
Overview
Best attempt to get client's IP address while keeping it DRY.
Notice
There is not a good out-of-the-box
solution against fake IP addresses, aka IP Address Spoofing.
You are encouraged to read the Advanced users section of this page and
use trusted proxy prefixes
and/or proxy count
features to match your needs, especially if you are
planning to include ipware
in any authentication, security or anti-fraud
related architecture.
You are also encouraged to use ip filtering alongside ipware
for optimal result.
How to install
npm install @fullerstack/nax-ipware
OR yarn add @fullerstack/nax-ipware
How to use
# In a view or a middleware where the `request` object is available
// In your js file (e.g. app.js)
import {Ipware} from '@fullerstack/nax-ipware';
const ipware = new Ipware();
app.use(function(req, res, next) {
req.ipInfo = ipware.getClientIP(req)
// { ip: '177.139.100.100', isPublic: true, isRouteTrusted: false }
// do something with the ip address (e.g. pass it down through the request)
// note: ip address doesn't change often, so better cache it for performance,
// you should have distinct session ID for public and anonymous users to cache the ip address
next();
});
Advanced users:
| Flags ⇩ | ⇩ Description |
| -------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| count
⇨ | : Total number of expected proxies (pattern: client, proxy1, ..., proxy2
): if count = 0
then client
: if count = 1
then client, proxy1
: if count = 2
then client, proxy1, proxy2
: if count = 3
then client, proxy1, proxy2 proxy3
|
| proxyList
⇨ | : List of trusted proxies (pattern: client, proxy1, ..., proxy2
): if proxyList = ['10.1.']
then client, 10.1.1.1
OR client, proxy1, 10.1.1.1
: if proxyList = ['10.1', '10.2.']
then client, 10.1.1.1
OR client, proxy1, 10.2.2.2
: if proxyList = ['10.1', '10.2.']
then client, 10.1.1.1 10.2.2.2
OR client, 10.1.1.1 10.2.2.2
|
| publicOnly
⇨ | : Returns only public and internet routable IP or null |
| Output Field ⇩ | ⇩ Description |
| -----------------: | :------------------------------------------------------------------------------- |
| ip
⇨ | : IP address of the client |
| isPublic
⇨ | : If ip
is public and internet routable, true
, else false
|
| isRouteTrusted
⇨ | : If proxy count
and/or proxyList
provided and matched, true
, else false
|
Precedence Order
The client IP address can be found in one or more request headers attributes. The lookup order is top to bottom and the default attributes are as follow.
// The default meta precedence order
export const IPWARE_HEADERS_IP_ATTRIBUTES_ORDER: string[] = [
'X_FORWARDED_FOR', // Load balancers or proxies such as AWS ELB (default client is `left-most` [`<client>, <proxy1>, <proxy2>`])
'HTTP_X_FORWARDED_FOR', // Similar to X_FORWARDED_TO
'HTTP_CLIENT_IP', // Standard headers used by providers such as Amazon EC2, Heroku etc.
'HTTP_X_REAL_IP',
'HTTP_X_FORWARDED',
'HTTP_X_CLUSTER_CLIENT_IP',
'HTTP_FORWARDED_FOR',
'HTTP_FORWARDED',
'HTTP_VIA',
'X-REAL-IP', // NGINX
'X-CLUSTER-CLIENT-IP', // Rackspace Cloud Load Balancers
'X_FORWARDED',
'FORWARDED_FOR',
'CF-CONNECTING-IP', // CloudFlare
'TRUE-CLIENT-IP', // CloudFlare Enterprise,
'FASTLY-CLIENT-IP', // Firebase, Fastly
'FORWARDED',
];
You can customize the order by providing your own list during initialization when calling new Ipware(options)
.
You can pass your custom list on every call, when calling the api to fetch the ip.
ipware.getClientIP(request, {
requestHeadersOrder: ['X_FORWARDED_FOR'],
});
ipware.getClientIP(request, {
requestHeadersOrder: ['X_FORWARDED_FOR', 'HTTP_X_FORWARDED_FOR'],
});
// ... etc
Private Prefixes
A default list that holds the private IP prefixes is called IPWARE_PRIVATE_IP_PREFIX
.
This list is used to determine if an IP address is public
or private
.
It is recommended that you send us any private
IP addresses that we have missed, to be included in the default list.
export const IPWARE_PRIVATE_IP_PREFIX: string[] = [
'0.', // messages to software
'10.', // class A private block
...[
// carrier-grade NAT (IPv4)
'100.64.',
'100.65.',
'100.66.',
'100.67.',
],
// many more prefixes
]
You can customize the private IP prefixes by providing your own list during initialization when calling new Ipware(options)
.
You can pass your custom list on every call, when calling the api to fetch the ip.
ipware.getClientIP(request, {
privateIpPrefixes: ['0.', '10.'], // your own private IP addresses
});
ipware.getClientIP(request, {
privateIpPrefixes: ['0.', '10.', '2001:10:'], // your own private IP addresses
});
// ... etc
Trusted Proxies
If your node server is behind one or more known proxy server(s), you can filter out unwanted requests
by providing a trusted proxy list
, or a known proxy count
.
You can customize the proxy IP prefixes by providing your own list during initialization when calling new Ipware(options)
.
You can pass your custom list on every call, when calling the proxy-aware api to fetch the ip.
// In the above scenario, use your load balancer IP address as a way to filter out unwanted requests.
const ipInfo = ipware.getClientIP(request, {
proxy: {
proxyList: ['177.139.233.132']
},
});
// If you have multiple proxies, simply add them to the list
const ipInfo = ipware.getClientIP(request, {
proxy: {
proxyList: ['177.139.233.100', '177.139.233.132']
},
});
// For proxy servers with fixed sub-domain and dynamic IP, use the following pattern.
const ipInfo = ipware.getClientIP(request, {
proxy: {
proxyList: ['177.139.', '177.140']
},
});
const ipInfo = ipware.getClientIP(request, {
proxy: {
proxyList: ['177.139.233.', '177.139.240']
},
});
// For proxy by ip address and count
const ipInfo = ipware.getClientIP(request, {
proxy: {
proxyList: ['177.139.', '177.140'],
count: 2
},
});
// For strict mode, we either return the ip that matches the proxy info, or none
const ipInfo = ipware.getClientIP(request, {
proxy: {
strict: true,
proxyList: ['177.139.233.', '177.139.240']
},
});
In the following example
, your public load balancer (LB) can be seen as a trusted
proxy.
`Real` Client <public> <-> <public> LB (Server) <private> <-----> <private> Node Server
^
|
`Fake` Client <private> <-> <private> LB (Server) <private> -+
Proxy Count
If your node server is behind a known
number of proxies, but your deploy on multiple providers and don't want to track proxy IPs, you still can filter out unwanted requests by providing proxy count
.
You can customize the proxy count by providing your count
during initialization when calling new Ipware(options)
.
You can pass your custom count
on every call, when calling the proxy-aware api to fetch the ip.
// In the above scenario, the total number of proxies can be used as a way to filter out unwanted requests.
const ipInfo = ipware.getClientIP(request, {
proxy: {
count: 1
},
});
// For proxy by count, and proxy list
const ipInfo = ipware.getClientIP(request, {
proxy: {
count: 1
proxyList: ['177.139.233.']
},
});
// For strict mode, we either return the ip that matches the proxy info, or none
const ipInfo = ipware.getClientIP(request, {
proxy: {
strict: true,
count: 1
},
});
In the following example
, your public load balancer (LB) can be seen as the only
proxy.
`Real` Client <public> <-> <public> LB (Server) <private> <---> <private> Node Server
^
|
`Fake` Client <private> ---+
Public IP Address ONLY (routable on the internet)
// For publicOnly mode, we either return the first public IP address based on order or none
const ipInfo = ipware.getClientIP(request, {
publicOnly: true
});
Originating Request
If your proxy server has a custom
configuration where the right-most
IP address is that of the originating client, you
can indicate right-most
as the order
when calling any api.
Please note that the de-facto standard
for the originating client IP address is the left-most
as per client, proxy1, proxy2
, and the right-most
proxy is the most
trusted proxy.
Running the tests
To run the tests against the current environment:
yarn nx test nax-ipware
License
Released under a (MIT) license.
Version
X.Y.Z Version
`MAJOR` version -- making incompatible API changes
`MINOR` version -- adding functionality in a backwards-compatible manner
`PATCH` version -- making backwards-compatible bug fixes