Generating HttpRequest from specific IP in Java

2020-06-23 11:23发布

问题:

I am using Apache HttpClient for generating Post request and submitting the data. Since remote application relays on IP address of the user that's submitting the data, I want to send post request for user specified IP address.

How do I configure this?

public static void loginUser(String username, String password, String ip) throws Exception{
      try {
            HttpClient client = new DefaultHttpClient();
            HttpPost httppost = new HttpPost("http://login.myapp.com/");

            // Request parameters and other properties.
            List<NameValuePair> params = new ArrayList<NameValuePair>(2);
            params.add(new BasicNameValuePair("username",username));
            params.add(new BasicNameValuePair("password", password));
            httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));

            // Execute and get the response.
            HttpResponse response = client.execute(httppost);
            HttpEntity entity = response.getEntity();

            if (entity != null) {
                //etc....
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

EDIT: To avoid confusion,

I want to include custom IP address in httprequest headers so that the end application knows that, this request [from my app] came from custom IP address but not from the IP address where my application is running

Let's say my application is running on server with ip address "1.1.1.0". Now my user is executing loginUser method with "test","test","199.199.199.0". Now the HTTP Request from the application to destination URL should go as its sent from "199.199.199.0"

回答1:

OP writes:

I want to include custom IP address in httprequest headers so that The end application knows that this request [from my app] came from custom IP address but not from the IP address where my application is running
...
Let's say I opened google.co.in, now google server knows this request came from my ip address. now if I use HttpClient in apache, how do i configure that ip address so that when google server reads, it will treat this request originally came from that ip address

You can't.

(This is actually the 4th interpretation that I wrote in my original answer below.)

The sender's IP address is not sent as an HTTP header. It's sent in a field in the IP protocol header. The server obtains the sender's IP address down low at the socket level, it does not obtain it from HTTP information.

And no, you could not fake your IP (it's called "spoofing") even if you wanted to. Java does not have native support for raw sockets, you cannot modify the information at the IP level. Even if you could (or you use JNI or some outbound packet filtering application or hardware), the nature of TCP makes IP spoofing useless for your situation (responses would be sent to the fake IP, as well as many other difficulties that are well beyond the scope of this answer).

So, no, you cannot do what you are trying to do. You either need to get special rules put in place for you by the administrators of the server you are trying to connect to, or you need to seriously rethink the design of your application.

Edit: Other Alternatives

I mentioned these in comments on the question but I'm including them here in my answer as well for completeness:

One possible solution, depending on your security requirements, is to set up VPN access for your users, so that users must establish a VPN connection first, and then run your web application on an internal server.

You could also have your web server connected to your network via VPN and access your internal login services directly through the VPN link, with the web application running on the WAN link.


This was my original answer before the OP clarified the requirements:

Not really clear what you are asking so I will answer the possibilities I can think of.

If you mean that want to let the user specify the IP address of the server you are sending the post to, just build the URL from the IP address:

HttpPost httppost = new HttpPost("http://" + ip + "/");

If you mean that you want the server to do something based on the user's IP address: The user's IP address will be available on the server side when the server receives the request, you don't need to send it explicitly. Exactly how to access that information, server side, depends on the server you are using.

If you mean that you want the user to be able to specify an IP address that is sent to the server, just send it like you send the other parameters:

params.add(new BasicNameValuePair("whatever", ip));

If you mean that you are logging in to a system that relies on the user's IP address, from your server on behalf of a remote user, and you want to pretend to be that remote user so that log in succeeds: You can't. The system that you are trying to log into has security measures in place to prevent exactly what you are trying to do. Perhaps it is possible for the owners of that system to put in an exception for your server's IP address; you'd have to ask them.



回答2:

This is simply not possible, because of how TCP works. It's about networking. It doesn't matter what tools / programming languages you use.
By trying to disguise yourself as another IP, TCP can't complete the handshake nor can send your data. With UDP, you can do this trick, but HTTP (web) protocol is based on TCP, so there's no use.

Some references for further reading:
TCP handshake
TCP details
UDP details



回答3:

If you have a multi-homed host, i.e. a host with more than one IP, you can choose which IP you want to use as the source-IP using RequestConfig.setLocalAddress.

For a specific request:

HttpClient httpClient = HttpClientBuilder.create().build();

HttpGet request = new HttpGet("https://www.cloudflare.com/cdn-cgi/trace");
RequestConfig config = RequestConfig.custom().setLocalAddress(localAddr).build();
request.setConfig(config);

httpClient.execute(request).getEntity().writeTo(System.out);

Or for the entire HttpClient:

RequestConfig config = RequestConfig.custom().setLocalAddress(localAddr).build();
HttpClient httpClient = HttpClientBuilder.create().setDefaultRequestConfig(config).build();

HttpGet request = new HttpGet("https://www.cloudflare.com/cdn-cgi/trace");
httpClient.execute(request).getEntity().writeTo(System.out);