Forwarding User IP through Nginx at Websocket

Alpha2k :

I'm using this Websocket library with the example from here to create multiple services based on websockets.

The main server taking the requests is an Nginx server which forwards the requests acording to their origin (domain based), so I can know for sure the requests received are for websockets.

The problem however is here:

public void onOpen(WebSocket ws, ClientHandshake handshake) {
    System.out.println("-------------------------------");
    System.out.println(ws.getRemoteSocketAddress());
    System.out.println("-------------------------------");
}

getRemoteSocketAddress will always return the nginx server IP, something like /192.168.1.100:43556

My nginx configuration is:

server{
    listen 80;
    server_name we.mydomain.com;
    access_log /var/log/nginx/access-ws-debug.log;
    error_log /var/log/nginx/error-ws-debug.log;

    set_real_ip_from  192.168.1.0/24;
    real_ip_header X-Real-IP;
    real_ip_recursive on;

    location / {
       proxy_pass http://192.168.1.101:54321;

       proxy_http_version 1.1;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header Host $http_host; #host
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_set_header Y-Real-IP $realip_remote_addr;

       proxy_set_header Upgrade $http_upgrade;
       proxy_set_header Connection "Upgrade";

       proxy_connect_timeout 1d;
       proxy_send_timeout 1d;
       proxy_read_timeout 1d;
    }
}

Is there any problem with the nxing configuration? Or is there any other way to get the IP of the user behind the websocket?


Solved thanks to Mark's answer. The following code is not related to the library mentioned. It's the "classic" web implementation in jsp without any library.

I modified the handshake to look like this:

@Override
public void modifyHandshake(
        ServerEndpointConfig config,
        HandshakeRequest request,
        HandshakeResponse response
) {
    HttpSession httpSession = (HttpSession) request.getHttpSession();
    config.getUserProperties().put(HttpSession.class.getName(), httpSession);
    config.getUserProperties().put("Headers",request.getHeaders());
}

And to get the Headers, just invoking this in the OnOpen:

@OnOpen
public void onOpen(final Session session, EndpointConfig config){ //This happens when javascript opens socket session
    Object list = config.getUserProperties().get("Headers");
    System.out.println("-------------------------------------");
    System.out.println(list);
    System.out.println("-------------------------------------");
}

The returned format for the headers is like the following (using my phone):

{upgrade=[websocket], 
accept-language=[en-US,en;q=0.9,es;q=0.8], 
cookie=[JSESSIONID=0BAE99DFDE5DD81D20CFF04E4257D7FE], 
sec-websocket-extensions=[permessage-deflate; client_max_window_bits], 
origin=[https://mywebsite.com], 
x-forwarded-for=[1.2.3.4], 
sec-websocket-version=[13], 
pragma=[no-cache], 
x-real-ip=[1.2.3.4], 
y-real-ip=[1.2.3.4], 
host=[mywebsite.com], 
connection=[Upgrade], 
sec-websocket-key=[ZroOewrBGrg660x7ocI+nog==], 
cache-control=[no-cache], 
accept-encoding=[gzip, deflate, br], 
user-agent=[Mozilla/5.0 (Linux; Android 8.0.0; SM-N950F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36]}

And the IP is geo-localizable near my area.

Hash :

It is not a trivial task to do, but your configuration looks OK you just have to get the original IP from the header you set (X-Real-IP).

import javax.websocket.*;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpoint;
import javax.websocket.server.ServerEndpointConfig;

@ServerEndpoint(value = "/test", configurator = Test.TestConfiguratior.class)
public class Test extends Endpoint {

    @Override
    public void onOpen(Session session, EndpointConfig endpointConfig) {
        Object o = endpointConfig.getUserProperties().get(TestConfiguratior.HEADER_NAME);
        //o should be the string object you are looking for
    }

    @OnMessage
    public void onMessage(Session session, String msg) {
        //do what u want
    }

    public static class TestConfiguratior extends ServerEndpointConfig.Configurator {
        static String HEADER_NAME = "X-Real-IP";

        @Override
        public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
            String firstFoundHeader = request.getHeaders().get(HEADER_NAME.toLowerCase()).get(0);
            sec.getUserProperties().put(HEADER_NAME, firstFoundHeader);
        }
    }
}

TL.DR.: You can use the javax.websocket.EndpointConfig#getUserProperties map to put data in it and retrieve it later. Initially I thought that this can cause some concurrency problems while using this exact code, but I was not able to reproduce it. Even the documentation recommends to do so this way: https://javaee.github.io/tutorial/websocket010.html

Update: This is a JSR 356 example, not specific for the mentioned framework.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=81970&siteId=1