According to the doc of CloudFront
(https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/RequestAndResponseBehaviorCustomOrigin.html), client IP can be the front, middle, end of X-Forwarded-For
header.
Is it rignt? Then how can I get real client IP?
Amazon CloudFront adds support for client IP address and connection port header. The CloudFront-Viewer-Address header is provided at no additional cost. You can use the header, along with other CloudFront headers, for analyzing, auditing, and logging purposes.
To view the current ranges, download ip-ranges. json . For more information, see AWS IP address ranges in the Amazon Web Services General Reference. Alternatively, you can view only the CloudFront IP ranges at https://d7uri8nf7uskq.cloudfront.net/tools/list-cloudfront-ips .
To set the header name to be used as the True-Client-IP for an application, log in to the Radware Cloud Services portal, and navigate to Settings > Applications, select an application, and then scroll down to the True Client IP section.
request. getHeader("X-FORWARDED-FOR") is always null even if property for sending x-forwarded-for is enabled on load balancer, and request. getRemoteAddr() is always giving the IP address of load balancer. When we disable ssl, this work fine, I got client IP, not the IP of the load balancer.
Is it right?
Not exactly.
CloudFront follows correct semantics for X-Forwarded-For
. Specifically, each system handling the request appends its client's address to the right. This means the rightmost address in X-Forwarded-For
in the request from CloudFront is always the address of the machine that connected to CloudFront.
If the client (the machine establishing the connection to CloudFront) includes an X-Forwarded-For
header in its request, that header may be forged, or it may be legitimate if the client is a proxy server, but you rarely have a way of knowing that... so either way, you should treat this as potentially valuable, but strictly non-authoritative.
The rightmost value (which may also be the only value) is the only value you can trust in the request you receive from CloudFront.
Generally speaking, parsing from the right, any address that is known to you and trusted to have correctly identified its upstream client can be removed from the list... but once you encounter the first untrusted address, right to left, that's the one you're looking for, since nothing to the left of that address can be trusted.
This means that if components in your stack -- such as Application Load Balancer or your web server are also adding X-Forwarded-For
, then you will need to account for what those components also add onto the right side of the value, modifying what CloudFront has supplied.
For example. Client sends:
X-Forwarded-For: a, b, c
CloudFront adds the client's IP d
:
X-Forwarded-For: a, b, c, d
ALB receives the request from CloudFront, so it adds the CloudFront egress address e
:
X-Forwarded-For: a, b, c, d, e
Then your web server adds the internal address of the balancer f
:
X-Forwarded-For: a, b, c, d, e, f
You can trust and remove f
as long as it is with the CIDR range of your balancer subnets.
You can trust and remove e
as long as it is in the CloudFront address ranges.
That leaves you withd
as the client address.
The values a
and b
and c
are almost worthless, in this example, because you can't trust their authenticity since they are to the left of the first (from the right) untrusted address... occasionally, they may be forensically useful, later, but you can't make any real-time decisions based on them.
This is how X-Forwarded-For
always works. Many developers seem to make naïve assumptions due to lack of understanding. Be certain you understand it before you use it for anything important.
In Lambda@Edge triggers, CloudFront gives you the client IP address in event.Records[0].cf.request.clientIp
. This is always just a single address, and is the same as the rightmost value of X-Forwarded-For
as the request leaves CloudFront headed to your origin (which may, as noted above, add additional values onto the right side).
My suggestion would be to use CloudFront provided headers, link - [https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-cloudfront-headers.html]
All you need to do first is Go to Cloudfront -> Select Distribution -> Behaviors -> and do the following in 'Cache key and origin requests'
Select 'CachingDisabled' for 'Cache policy' dropdown, if you don't want anything to get cached. I personally faced problems in my app, if I didn't select this option.
For Origin Request Policy do the following -
Create a new Policy like 'Origin-Policy-For-Cloudfront' and select 'CloudFront-Viewer-Address' and checkout other options as well.
It'll look something like this -
Now, open conf.d/node.conf or nginx.conf, whereever you have written your 'server -> /location', and simply write the following -
server {
listen 80;
server_name my-server CLOUDFRONT_URL;
location / {
proxy_set_header X-Client-IP $http_CloudFront_Viewer_Address;
proxy_set_header Host $http_host;
proxy_pass "http://127.0.0.1:
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
On the NodeJs Backend, you can fetch the Client IP in the request as follows -
exports.get = (req, res, next) => {
console.log('Clinet IP:', req.headers['x-client-ip']);
}
This is an easier method to get the client Ip rather than messing around with Cloudfront CIDR and all.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With