why ServletRequest.getRemoteAddr cannot be forged? - java

I am trying to find the client's IP. And I was told that 'request.getHeader("HTTP_X_FORWARDED_FOR")' cannot be trusted since it may be forged and I should use request.getRemoteAddr instead.(In my case it's ok to just get the proxy's IP)
So my question is:
why ServletRequest.getRemoteAddr cannot be forged?
another question:
what's the difference between HTTP_X_FORWARDED_FOR and X_FORWARDED_FOR?

If you do request.getRemoteAddr();
and if the user is behind a proxy server or accessing your web server through a load balancer then the above code will get the IP address of the proxy server or load balancer server, not the original IP address of a client.
So if
In my case it's ok to just get the proxy's IP
you are ok with this then request.getRemoteAddr(); is enough.
But in Ideal case you should try this
//is client behind something?
String ipAddress = request.getHeader("X-FORWARDED-FOR");
if (ipAddress == null) {
ipAddress = request.getRemoteAddr();
}
X_FORWARDED_FOR
The X-Forwarded-For (XFF) HTTP header field is a de facto standard for identifying the originating IP address of a client connecting to a web server through an HTTP proxy or load balancer.
HTTP_X_FORWARDED_FOR
A header HTTP_X_FORWARDED_FOR is set by proxy servers to identify the ip-address of the host that is making the HTTP request through the proxy.
In short they're all the same header, just referred to differently by various implementations. For more view this : HTTP Headers: What is the difference between X-FORWARDED-FOR, X_FORWARDED_FOR and HTTP_X_FORWARDED_FOR?

Related

Spring Security - Token authentication with request host name

I have an application implemented with Spring Boot, where I use Spring Security for authentication. I already have "token based" authentication in place, where clients are required to retrieve a token, and then use that token to authenticate in subsequent requests.
I would like to enhance this so that a token could be restricted to a specific hostname, so that is can only be used for requests from that host. This is similar to what the google maps API does with its API keys, where it is possible to restrict them by IP or host name.
Here is the code I have implemented to try to retrieve the request's host name
public String getClientHostName(HttpServletRequest request) {
String hostName = null;
// get the request's IP address
String clientAddress = httpRequest.getRemoteAddr();
String xfHeader = httpRequest.getHeader("X-Forwarded-For");
if (xfHeader != null) {
clientAddress = xfHeader.split(",")[0];
}
// try to resolve the host name from the IP address
try {
InetAddress address = InetAddress.getByName(clientAddress);
hostName = address.getHostName();
} catch (UnknownHostException e) {
logger.error("Failed to get the host name from the request's remote address. ", e);
}
return hostName;
}
I have 2 issues right now:
This code does not always manage to retrieve the hostname. Sometimes it just returns the IP address. I understand this may be down to some IP spoofing check the InetAddress class does.
When testing requests from different hosts, I do not always get the IP address I am expecting. I often get the IP of another host that is forwarding the request (which I thought would be solved by checking "X-Forwarded-For"). This makes me wonder how to even retrieve the IP of the host that is the real originator of the request.
Is there a reliable way to check the host name of the originator of a request?
have you tried getting hostname by String referrer = request.getHeader("referer"); ?
Also, on client side also you can add a snippet to find out the hostname in the headers.
Or you can provide below code to be added on client side and on server you can read the value of domain which will return hostname
<input type="button" value="Register" onClick="call()"/>
<script>
function call(){
var domain=window.location.hostname;
window.open('http://<your-hostname>/register?domain='+domain,'_self');
}
</script>

Does IP Address also gets passed in the Http Header with RestTemplate call by default or not?

I am making a HTTP url call using RestTemplate with the below simple code. Here url is one of our Service which will be extracting IP Address from the header.
String response = restTemplate.getForObject(url, String.class);
So my question is does the IP Address also gets passed in the HTTP Header while making the url call or not in the way I am doing as shown above?
My service is running on machineB so if I am hitting that url from machineA using the above RestTemplate code does machineA IP Address gets passed in the header or not?
Or Do we need to do any extra stuff to pass the IP Address in the header while making the url call?
The IP address of the client is not automatically passed in an HTTP standard header, as the HTTP server would have no need for this information. The IP address of the client is already available to the server via the IP packets used to transport the HTTP request.
If you want to have the client send it's IP address in an HTTP header you will have to create a custom header and fill it in with each request.

How to distinguish between Known IP and unknown IP

i need to develop a web application that can identify a known machine and unknown by storing a pair(sourceIP,valid username) at server side for which previous login was successful.when anyone login from unknown machine how can be identified.web app is hosted in local host.is it possible to get the client ip.when retrieving client IP i get only 127.0.0.1 which is localhost.anyone having any idea...?
The short answer is that you can't always get the real client IP address.
If the client has an IP address of its own and connects directly to the server, then HttpServletRequest.getRemoteAddr() should return it. However:
If the client's requests reach the server via a proxy or reverse proxy, then getRemoteAddr() will return the first upstream proxy address.
If the client addresses the server as localhost when the request will come from localhost.
If the client is behind a NAT gateway or an IPv4 <-> IPv6 bridge you are liable to see the IP address of the gateway or bridge.
Then there is the problem that the IP address might be spoofed.
In short security schemes that rely on knowing the real client IP address are often problematic.
If your problem is due to a reverse proxy (and seeing 127.0.0.1 would imply that), you can have the reverse proxy add a request header to the request to say what remote IP address it saw. Then the server needs to use that header instead of getRemoteAddr(). However, that won't help if the proxy didn't see the real client IP address.
In Servlet you do something like this:
public class GetAddress extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
String ip = request.getRemoteAddr();
// now you can check if the ip exists and if not store it or do other usefull stuff ...
}
}

Rest - how get IP address of caller

I am writing a Java Rest Web Service and need the caller's IP Address. I thought I saw this in the cookie once but now I don't see it. Is there a consistent place to get this information?
I saw one example of using an "OperationalContext" to get it but that was not in java.
Inject a HttpServletRequest into your Rest Service as such:
import javax.servlet.http.HttpServletRequest;
#GET
#Path("/yourservice")
#Produces("text/xml")
public String activate(#Context HttpServletRequest req,#Context SecurityContext context){
String ipAddressRequestCameFrom = requestContext.getRemoteAddr();
// header name is case insensitive
String xForwardedForIP = req.getHeader("X-Forwarded-For");
// if xForwardedForIP is populated use it, else return ipAddressRequestCameFrom
String ip = xForwardedForIP != null ? xForwardedForIP : ipAddressRequestCameFrom;
System.out.println("IP is "+ip);
// get the host name the client contacted. If the header `Host` is populated the `Host` header is automatically returned.
// An AWS ALB populated the Host header for you.
String hostNameRequestCameFrom = req.getServerName();
System.out.println("Host is "+hostNameRequestCameFrom);
//Also if security is enabled
Principal principal = context.getUserPrincipal();
String userName = principal.getName();
}
As #Hemant Nagpal mentions, you can also check the X-Forwarded-For header to determine the real source if a load balancer inserts this into the request.
According to this answer, the getHeader() call is case insensitive.
You can also get the servername that the client contacted. This is either the DNS name or the value set in the Host header with an OSI layer 7 load balancer can populate.
1. Example: no headers are populated
curl "http://127.0.0.1:8080/"
returns
IP is 127.0.0.1
Host is 127.0.0.1
2. Example: X-Forwarded-For and Host headers are populated
curl --header "X-Forwarded-For: 1.2.3.4" --header "Host: bla.bla.com:8443" "http://127.0.0.1:8080/"
returns
IP is 1.2.3.4
Host is bla.bla.com
I think you can get the IP through the request object.
If I'm not mistaken, request.getRemoteAddr() or so.
You could do something like this:
#WebService
public class YourService {
#Resource
WebServiceContext webServiceContext;
#WebMethod
public String myMethod() {
MessageContext messageContext = webServiceContext.getMessageContext();
HttpServletRequest request = (HttpServletRequest) messageContext.get(MessageContext.SERVLET_REQUEST);
String callerIpAddress = request.getRemoteAddr();
System.out.println("Caller IP = " + callerIpAddress);
}
}
Assuming you are making your "web service" with servlets, the rather simple method call .getRemoteAddr() on the request object will give you the callers IP address.
If your application is running on a webserver that is located behind a reverse proxy or load balancer, then that proxy can be configured to inject the requested IP address in a request header. Different reverse proxies can inject different headers. Consult the documentation for your proxy server. We listed a couple of the most used in our example below but this is by no means a complete list.
When your client uses a (forward) proxy, then it might insert headers to say what the client IP addres is. Or it might not. And the IP address inserded here might be incorrect.
This means that the value you get by calling request.getRemoteAddr() is the IP address of the immediate upstream source of the request.
As we said, there are many headers for different proxies in use, but x-forwareded-for is most likely to be inserted by a proxy.
As a last note, even if you get an IP address either from the header or from request.getRemoteAddr() it is not guarenteed to be the client IP address. e.g.: if your proxy does not include the IP address of the client then you’ll get the IP address of the proxy or load balancer. If your client works on a private network and connect to the internet via a NAT gateway, then the IP address in the HTTP request will be an address of the NAT server. Or even for a hacker it is quite easy to inject a header with a different IP address. So this means that you cannot reliably find out the IP address of the system that the request originated from.
private static final String[] IP_HEADER_CANDIDATES = {
"X-Forwarded-For",
"Proxy-Client-IP",
"WL-Proxy-Client-IP",
"HTTP_X_FORWARDED_FOR",
"HTTP_X_FORWARDED",
"HTTP_X_CLUSTER_CLIENT_IP",
"HTTP_CLIENT_IP",
"HTTP_FORWARDED_FOR",
"HTTP_FORWARDED",
"HTTP_VIA",
"REMOTE_ADDR" };
public static String getClientIpAddress(HttpServletRequest request) {
for (String header : IP_HEADER_CANDIDATES) {
String ip = request.getHeader(header);
if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
return ip;
}
}
return request.getRemoteAddr();
}

How to get the subnet ip adress from http request

I'm writing a web application, I need to do a audit log for all the actions in the application. For this purpose I need to get the IP Address of the client systems.
I'm using request.getRemoteAddr() to get the remote IP Address. But this has a problem, if the client is behind a proxy this method will give the IP of the proxy system.
When I did some search I found a header attribute called 'X-FORWARDED-FOR' in the HttpRequest object.
Can somebody tell me how exactly this header property works and how can I used this header to get the IP address of the client system.
Thank you
getRemoteIP returns the remote IP address of the user (assuming all HTTP intermediaries are well behaved wrt XFF header).
String getRemoteIP(HttpServletRequest request) {
String xff = request.getHeader("X-Forwarded-For");
if (xff != null) {
return xff.split("[\\s,]+")[0];
}
return request.getRemoteAddr();
}
The client's proxy - typically a firewall or somesuch - will populate the x-forwarded-for header with the ip it receives from its client, which is typically, but is not required to be (in the case of a user going through multiple proxies or firewalls) the ip of the user's machine.
'X-FORWARDED-FOR' is used for identifying the originating/actual IP address of a client connecting to a web server through an HTTP proxy.
You can simply use the value for this attribute to find out the originating client IP, even if it's behind a proxy.

Categories

Resources