I'm writing a java-websocket server as a cryptocurrency client.
For security reasons, I'd like to restrict access to the local machine.
Is there a way to restrict access to a java-websocket server by IP or hostname?
If so, how?
You should specify your listening ip to 127.0.0.1 thus it wont be possible to connect from the outside.
Edit
Looking at the example ChatServer.java the binding happens with
ChatServer s = new ChatServer( port );
The class implements two constructors:
public ChatServer( int port ) throws UnknownHostException {
super( new InetSocketAddress( port ) );
}
public ChatServer( InetSocketAddress address ) {
super( address );
}
So you could also call the server with an inetSocketAddress. Create one thats binds to localhost:
new ServerSocket(9090, 0, InetAddress.getByName(null));
and then call the server with that instead of just the port.
So replace
ChatServer s = new ChatServer( port );
with
InetSocketAddress myLocalSocket = new ServerSocket(9090, 0, InetAddress.getByName(null));
ChatServer s = new ChatServer( myLocalSocket );
in your example and it should work.
The accepted answer by Max will prevent connections to your socket from outside, but there is another attack vector that you should consider.
A connection to your localhost WebSocket can be made by JavaScript hosted on any outside website. If your local user is tricked into visiting a remote site, the HTML/JavaScript hosted by that site will be able to communicate with your local web socket.
You may be able to mitigate this by restrict connections based Origin header value, which will indicates the script origin address generating the WebSocket connection request. Keep in mind that the Origin header is optional and you are relying on the browser to set it appropriately to where the script came from.
Related
I have been testing the SCTP support on Java + lksctp.
I wrote a simple client in order to see just the inital setup of a SCTP association which is basically the "INIT" and "INIT ACK".
I have tested 2 ways for a Client to send the "INIT" to a SERVER which is basically:
create the SctpChannel object with "open(SocketAddress)"
try {
InetSocketAddress socketAddress = new InetSocketAddress("192.168.52.197", 2905);
SctpChannel sctpChannel = SctpChannel.open(socketAddress,1,1);
sctpChannel.bind(new InetSocketAddress("192.168.1.251",2906));
sctpChannel.connect(socketAddress, 1 ,1);
so in this way, I can see in Wireshark that I have the "IPv4 Address parameter" for all my network interfaces (3 as you can see bellow), but the Source Port is getting a aleatory port number instead the 2906 as I would like to have and it's in the bind.
So... once the bind of local IP/Port is happening after the "open"... so I have changed the code to:
create the SctpChannel object which just "open()"
binding the local client IP and Port
"connect" to the remote Server IP and Port
try {
InetSocketAddress socketAddress = new InetSocketAddress("192.168.52.197", 2905);
SctpChannel sctpChannel = SctpChannel.open();
sctpChannel.bind(new InetSocketAddress("192.168.1.251",2906));
sctpChannel.connect(socketAddress, 1 ,1);
In this way, I can see in wireshark that Source/Destination ports are expected (2906/2905), but the INIT does not have the "IPv4 Address parameter".
So does anyone know why the 2nd code I'm missing the "IPv4 address parameter" in the INIT ? Do I miss something?
Any help would be really welcome.
Thanks.
IP addresses within INIT/INIT_ACK chunks are optional parameters. In case your endpoints are signglehomed IP address might not be included in the INIT/INIT_ACK chunk. The remote end still can retrieve information about peer address from the IP header.
Fundamentally the reason of this behaviour is what parameters you pass to open(). Open() without any parameters and open() with remote address specified works in a different way.
If you call SctpChannel.open(socketAddress,1,1) with socket address for the remote end it effectively open channel and connects to remote end (see open documentation. Your bind() and connect() calls in this case are pretty useless. So since there were no bind() call prior to establishing the connection you are sort of using "default" endpoint with random port (56044) and IP addresses of all available interfaces.
In second case, when you don't specify socketAddress for open() it just open the channel but does not connect to remote end at this stage. So your bind() call successfully specify endpoint details (port and IP address) and when you call connect() it is actually using the endpoint you just created (192.168.1.251:2906) to setup connection with remote end.
I have a server.java and a client.python file. When I try the following, however, I get a "[Errno 10013] An attempt was made to access a socket in a way forbidden by its access permissions" error. Is there a way around this? Why is this happening?
client.py
sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
sockRecv = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
sock.bind((socket.gethostname(),4000))
sockRecv.bind((socket.gethostname(),4000 + 1))
server.java
recvSocket = new DatagramSocket(4000);
sendSocket = new DatagramSocket(4000 + 1);
What your code is doing doesn't make sense, to me.
The IP address + port represents an end-point for datagram communication. If two applications were able to bind to the same end-point, which of them would receive the packets sent to the end-point? One of them? Both of them?
UDP is not a multi-cast protocol .... unless you bind to a multicast IP address.
Based on hints in your code (names of variables) I think you are trying to set up message passing between two applications on the same host. If so you should do this:
Application A binds to port P1 and sends messages to port P2
Application B binds to port P2 and sends messages to port P1.
There is no need for applications A and B bind to the same end-point; i.e. the same port ... to do what I think you are trying to do.
I am using the utility sshuttle to access internet on my computer.
sudo sshuttle --dns -vr user#172.16.30.30 0/0
I have a simple java client server program
Client (My computer running sshuttle)
// client ip is 172.16.23.6
class client {
public static void main(String args[]) {
Socket s = new Socket("172.16.30.20",port); // different server
}
}
The server program, running on 172.16.30.20
class server {
public static void main(String args[]) {
ServerSocket s = new ServerSocket(port);
Socket cl = s.accept();
System.out.println(cl);
}
}
When I run the the server and connect the client, the IP address which the socket cl holds is 172.16.30.30 (IP of server to which I did sshuttle) instead of its own IP which is 172.16.23.6
When I stop sshuttle, the program works fine and the correct IP address is displayed.
I have to run both the programs simultaneously but am unable to do so.
You are out of the luck. sshuttle is like a proxy. The sshuttle server creates completely independent TCP connection from 172.16.30.30 to 172.16.30.20 and it copies incoming data from client connection to this connection. Your server 172.16.30.20 cannot get the information about the real client address because it is present neither in IP nor in TCP header. Your java server is able read sender address from the IP header but it is IP address of host that established the connection and it is 172.16.30.30 (sshuttle server).
Application protocols like HTTP have mechanism how to indicate the real client IP address. HTTP proxy may add HTTP header X-Forwarded-For and server then may learn the client IP from it. But it is possible only if application proxy adds this information to the forwarded data. sshuttle is application protocol independent so it cannot add such information.
I have a C# WPF application that uses TCPListener to start a Server in my computer, and an android app that works as a client. It works perfectly when I start the server and emulate the app in my computer, but most of the time it just doesn't work when I use my smartphone to connect to my computer, it only works some times after I restarted my router DHCP and my smartphone.
If you need, here's the connection code
Server:
private static IPAddress ipAd;
private static TcpListener server;
private static TcpClient client;
public static void start() {
//Already tried with both
ipAd = IPAddress.Parse(TCPServer.GetLocalIPAddress());
//ipAd = IPAddress.Parse("127.0.0.1");
server = new TcpListener(ipAd, 1209);
client = default(TcpClient);
try {
server.Start();
Console.WriteLine("Server started");
} catch {
Console.WriteLine("Failed to start server");
}
Client:
Socket socket = null;
String response = new String();
try{
//connect This ipAddress is the same in my desktop
InetAddress ipAd = InetAddress.getByName(ipAddress);
socket = new Socket(ipAd, 1209);
//send
DataOutputStream DOS = new DataOutputStream(socket.getOutputStream());
DOS.write(message.getBytes());
}
...
Thanks for your time, I've should had dedicated more to my Computer Networks class...
Should I redirect some specific port? Have some specific configurations in my router/firewall? I think I'm missing something
This would work when your devices located in the same network in terms of IP routing. However even part of the most simple SOHO grade WiFi routers/AP enable so called device isolation, denying access from wifi devices in the network access between them or to clients, connected with ethernet.
To make this setup work reliably you need to ensure the following:
Use external address of your router in the mobile application. (You can discover it browsing http://whatismyip.org from the server)
Setup port forwarding in your router for particular port to particular IP in your internal network.
As for privided source code, you'd rather use 0.0.0.0 as bind address in the server app, because default .NET implementation will select first available IP address and it may be not the one you're using for connection in the mobile app or not related to the same network. This approach may have security and convenience (coexistence) problems in case of complex networking setup, but will work good for most of the cases.
In our application, we are using RMI for client-server communication in very different ways:
Pushing data from the server to the client to be displayed.
Sending control information from the client to the server.
Callbacks from those control messages code paths that reach back from the server to the client (sidebar note - this is a side-effect of some legacy code and is not our long-term intent).
What we would like to do is ensure that all of our RMI-related code will use only a known specified inventory of ports. This includes the registry port (commonly expected to be 1099), the server port and any ports resulting from the callbacks.
Here is what we already know:
LocateRegistry.getRegistry(1099) or Locate.createRegistry(1099) will ensure that the registry is listening in on 1099.
Using the UnicastRemoteObject constructor / exportObject static method with a port argument will specify the server port.
These points are also covered in this Sun forum post.
What we don't know is: how do we ensure that the client connections back to the server resulting from the callbacks will only connect on a specified port rather than defaulting to an anonymous port?
EDIT: Added a longish answer summarizing my findings and how we solved the problem. Hopefully, this will help anyone else with similar issues.
SECOND EDIT: It turns out that in my application, there seems to be a race condition in my creation and modification of socket factories. I had wanted to allow the user to override my default settings in a Beanshell script. Sadly, it appears that my script is being run significantly after the first socket is created by the factory. As a result, I'm getting a mix of ports from the set of defaults and the user settings. More work will be required that's out of the scope of this question but I thought I would point it out as a point of interest for others who might have to tread these waters at some point....
You can do this with a custom RMI Socket Factory.
The socket factories create the sockets for RMI to use at both the client and server end so if you write your own you've got full control over the ports used. The client factories are created on the server, Serialized and then sent down to the client which is pretty neat.
Here's a guide at Sun telling you how to do it.
You don't need socket factories for this, or even multiple ports. If you're starting the Registry from your server JVM you can use port 1099 for everything, and indeed that is what will happen by default. If you're not starting the registry at all, as in a client callback object, you can provide port 1099 when exporting it.
The part of your question about 'the client connections back to the server resulting from callbacks' doesn't make sense. They are no different from the original client connections to the server, and they will use the same server port(s).
Summary of the long answer below: to solve the problem that I had (restricting server and callback ports at either end of the RMI connection), I needed to create two pairs of client and server socket factories.
Longer answer ensues:
Our solution to the callback problem had essentially three parts. The first was the object wrapping which needed the ability to specify that it was being used for a client to server connection vs. being used for a server to client callback. Using an extension of UnicastRemoteObject gave us the ability to specify the client and server socket factories that we wanted to use. However, the best place to lock down the socket factories is in the constructor of the remote object.
public class RemoteObjectWrapped extends UnicastRemoteObject {
// ....
private RemoteObjectWrapped(final boolean callback) throws RemoteException {
super((callback ? RemoteConnectionParameters.getCallbackPort() : RemoteConnectionParameters.getServerSidePort()),
(callback ? CALLBACK_CLIENT_SOCKET_FACTORY : CLIENT_SOCKET_FACTORY),
(callback ? CALLBACK_SERVER_SOCKET_FACTORY : SERVER_SOCKET_FACTORY));
}
// ....
}
So, the first argument specifies the part on which the object is expecting requests, whereas the second and third specify the socket factories that will be used at either end of the connection driving this remote object.
Since we wanted to restrict the ports used by the connection, we needed to extend the RMI socket factories and lock down the ports. Here are some sketches of our server and client factories:
public class SpecifiedServerSocketFactory implements RMIServerSocketFactory {
/** Always use this port when specified. */
private int serverPort;
/**
* #param ignoredPort This port is ignored.
* #return a {#link ServerSocket} if we managed to create one on the correct port.
* #throws java.io.IOException
*/
#Override
public ServerSocket createServerSocket(final int ignoredPort) throws IOException {
try {
final ServerSocket serverSocket = new ServerSocket(this.serverPort);
return serverSocket;
} catch (IOException ioe) {
throw new IOException("Failed to open server socket on port " + serverPort, ioe);
}
}
// ....
}
Note that the server socket factory above ensures that only the port that you previously specified will ever be used by this factory. The client socket factory has to be paired with the appropriate socket factory (or you'll never connect).
public class SpecifiedClientSocketFactory implements RMIClientSocketFactory, Serializable {
/** Serialization hint */
public static final long serialVersionUID = 1L;
/** This is the remote port to which we will always connect. */
private int remotePort;
/** Storing the host just for reference. */
private String remoteHost = "HOST NOT YET SET";
// ....
/**
* #param host The host to which we are trying to connect
* #param ignoredPort This port is ignored.
* #return A new Socket if we managed to create one to the host.
* #throws java.io.IOException
*/
#Override
public Socket createSocket(final String host, final int ignoredPort) throws IOException {
try {
final Socket socket = new Socket(host, remotePort);
this.remoteHost = host;
return socket;
} catch (IOException ioe) {
throw new IOException("Failed to open a socket back to host " + host + " on port " + remotePort, ioe);
}
}
// ....
}
So, the only thing remaining to force your two way connection to stay on the same set of ports is some logic to recognize that you are calling back to the client-side. In that situation, just make sure that your factory method for the remote object calls the RemoteObjectWrapper constructor up top with the callback parameter set to true.
I've been having various problems implementing an RMI Server/Client architecture, with Client Callbacks. My scenario is that both Server and Client are behind Firewall/NAT. In the end I got a fully working implementation. Here are the main things that I did:
Server Side , Local IP: 192.168.1.10. Public (Internet) IP 80.80.80.10
On the Firewall/Router/Local Server PC open port 6620.
On the Firewall/Router/Local Server PC open port 1099.
On the Router/NAT redirect incoming connections on port 6620 to 192.168.1.10:6620
On the Router/NAT redirect incoming connections on port 1099 to 192.168.1.10:1099
In the actual program:
System.getProperties().put("java.rmi.server.hostname", IP 80.80.80.10);
MyService rmiserver = new MyService();
MyService stub = (MyService) UnicastRemoteObject.exportObject(rmiserver, 6620);
LocateRegistry.createRegistry(1099);
Registry registry = LocateRegistry.getRegistry();
registry.rebind("FAManagerService", stub);
Client Side, Local IP: 10.0.1.123 Public (Internet) IP 70.70.70.20
On the Firewall/Router/Local Server PC open port 1999.
On the Router/NAT redirect incoming connections on port 1999 to 10.0.1.123:1999
In the actual program:
System.getProperties().put("java.rmi.server.hostname", 70.70.70.20);
UnicastRemoteObject.exportObject(this, 1999);
MyService server = (MyService) Naming.lookup("rmi://" + serverIP + "/MyService ");
Hope this helps.
Iraklis