Websocket call timeout on Javascript Client - javascript

I'm using websockets for the first time and am unsure what I am doing wrong. Due to my IP being dynamic, I am using the following websocket call serverside:
$echo = new echoServer("myurl.com","9000");
and the following call clientside:
socket = new WebSocket("wss://myurl.com:9000");
I get a timeout err even though the server is completely unoccupied. Does anyone know why?I feel this is a basic error

That specific server, PHP-Websockets, does not provide support for the wss:// protocol (secure connection, similar to https:// for HTTP traffic).
Change the connection line to:
socket = new WebSocket("ws://myurl.com:9000");
Alternatively, if you need TLS support, PHP-Websockets might not be the best server for you.
I made the decision to not support TLS in PHP-Websockets because I did not know of any robustly tested, battle hardened PHP packages that provide access to the OpenSSL libraries. I have changed my mind as of 5 minutes ago, and will implement TLS using the built in PHP OpenSSL functions, but this will take time to implement and will require several testers. If you don't want to wait, don't wait.
I do not want people to think that their data is secure when I simply can't guarantee it.
Also, not specifically causing a failure but still an issue: In your server-side code, you should change instantiating the server's object to:
$echo = new echoServer("0.0.0.0", "9000");
The reason is that the IP address is setting the server's listen address. The listen address of "0.0.0.0" gets translated to "listen on all IP addresses that this machine can listen to." That means that, besides just your own public IP, it will also listen to 127.0.0.1, and if you have a second network card that has a different IP address assigned to it, you can receive traffic from that as well.
However, because of PHP's weak typing, when socket_bind() attempts to convert the IP address into its binary representation, but finds a string instead, it silently converts it to 0, which is equivalent to the IP address 0.0.0.0.
(I previously thought that socket_bind() was performing a DNS lookup to get the IP address. I was very wrong. Such weak typing on the part of PHP, and especially the assumptions made by developers like me, is the cause of many security holes.)

Related

Maintain communication between two clients even if their IP addresses change

I'm trying to figure out if it is possible to have something like this scenario:
Say we have two people, Alice and Bob. Alice wants to send some data (doesn't matter what this data is) to Bob, and vice versa. I know that WebRTC can be used to serverless-ly exchange messages, but that requires Alice and Bob knowing each other's IP addresses. Now, it's relatively easy for Alice and Bob to share their IP addresses once, to initialize a connection, but what happens if one of them happens to connect to a different network; maybe Bob is in a coffee shop, for instance, and his IP address is thus different? The previously initialized connection wouldn't be to his current IP address, so they'd have to reinitialize the connection; but how?
It would seem to me that there would already need to be some sort of preexisting communication between the two so they could share their IP addresses, but then why not just communicate through the method they communicate their IP addresses instead? Alternatively, there could be a server that connects the two, but that defeats the serverless part of the system.
So, is there any way to maintain communication between two clients even if they happen to change networks, and thus IP addresses? Perhaps there is a more fixed method of identifying devices than their IP addresses, like I've seen in this SO answer, but it's years old, so maybe there's something new? I'd be implementing this in JS, across multiple devices/OSs, so that answer probably wouldn't work. Any ideas/examples would be greatly appreciated; I mainly want to know if this is even possible, and, if so, how.
Simple Answer
No, while this is possible, it is unrealistic and not needed. See my longer explanation below. Also, if you really want to do this, although it is possible through QUIC, it’s not likely to be needed (as explained below).
Longer Answer/Question to think about
In short, this is not a needed feature of WebRTC. Let me ask you a question:
Alice and Bob are in a data channel, exchanging chat messages over WebRTC. To create a WebRTC connection, you need to use an ice server ( first link, second link ) to get both Alice and Bob to, to quote Wikipedia:
...to find ways for the two computers to talk to each other as directly as possible..
This means that it will use Alice’s current IP address to make an offer to Bob through a STUN or TURN server. If, like you said, Alice were to change IP addresses, she would need to change location. That means that she will need to move a sufficient distance so that the IP address will change. In practice, this probably means that she goes in a car and drives somewhere. If not, she calls an Uber or a cab or rides her bike. In most of these scenarios, she will need to close her computer, hence ending the p2p connection. If, by some weird wizardry, she doesn’t close her computer/the connection, the browser will very likely refresh, hence re-connecting to the WebRTC data channel from the new IP address. When will you need to create a WebRTC data channel and handle IP changes? Long explanation coming to a conclusion, clients changing IP addresses without ending/resetting the connect just doesn’t happen in practice.
If you want to look into other alternatives, here are some examples:
ALTERNATIVES
Adding an IP event listener ★
Now this isn’t an actual global variable that you can check, but you can use an online API (some are listed here) to check the user’s IP address, store it in a variable (or localStorage), and check if the IP changes. In a loop, you would do some simple logic to check If it does, you reset the WebRTC connection, if not, you keep the loop going.
Using a “piping” server
You can set up a simple chat by using a http/https server, already set up, explained here, called a piping server. You can look at the article for more information, but it promotes a serverless chat system (can be used without creating a server) that isn’t exposed to the difficulties of changing IP addresses. However, you need to know the peer’s ID, and they need to know your ID, which effectively makes solution obsolete because you need to have some sort of communication before establishing this simple chat.
Using Node.js, Websockets, and/or Socket.io ★
If you want to create a simple chat app or create a data channel, Node.js and Socket.io is the way to go. This is super simple, however, it involves a server, which is why I left it for last. However, I highly recommend this for ease and simplicity, and is not reliant on IP addresses. See here for a very good starting immersion into Node.js and the Express framework. I am far from an expert from Websockets, but MDN is always a good place to start. However good Websockets are, I think that Socket.io is much easier for beginners, so if you are willing to sacrifice a bit of speed over simplicity, you should start here. These are all good server-side chat starting points.
Links
Simple Answer
QUIC connection migration
IP Listener
SO Question,
Ice Servers
MDN docs, Wikipedia
Piping Server
Simple article, Github repo
Node.js, Websockets, and Socket.io
Node.js and Express setup, Websocket intro, and Socket.io intro
All alternatives that are starred (★) are personally recommended.
Yes, It is possible.
You need to use FQDN (or a sub-domain) instead of IP Address and a DNS server, and a client side util or tool to update DNS record while IP Address changing.
There's free solutions on the web like no-ip.com, cloud-flare and etc.
A more modern approach to this would be using QUIC for transport. It has a session ID in the payload and uses UDP as the transport. This handles the very common case where a NAT will change it's Public IP. From Cloudflare's blogpost:
One of the features QUIC is intended to deliver is called “connection migration” and will allow QUIC end-points to migrate connections to different IP addresses and network paths at will.
So assume Alice and Bob are sending messages via QUIC and their connection is given a session ID. Alice's NAT changes it's public IP and source port. Since UDP is being used, Alice's messages still are being sent to Bob's Public IP. Bob receive these UDP messages and looks at the embedded QUIC header and sees that it contains the same session ID as when he was speaking to Alice. Bob then starts using Alice's new public IP and port as a destination for the conversation.
Naturally this seems open to redirection attacks, but there is crypto layered on top of these mechanisms to prevent this and other attacks.
References:
Cloudflare Blog
Amazing blog on NAT behavior and setting up initial connectivity behind them
QUIC connection migration

nodejs ws library -- how to prevent brute force attack (both for passwords and for crashing)

I'm trying to make an application with NodeJS which heavily depends on users connecting to it via the typcial WebSocket protocol from their browsers, I'm using the ws library for this in nodeJS.
The actual application works fine, and I'm able to disconnect any user (if I can detect that the current IP address has already connected), and authorize it with a user name and password (all taken care of on the server side, after they send the username and password via the websocket, and I can even make a timer on the server side to prevent the client from brute forcing the server to try to authorize itself with a username and password); however, I have not yet found a way to block the connections from happening in the first place.
What to I mean? For example, someone, on the client side, can open up their javascript console and simply type something like:
setInterval(function() {
new WebSocket("ws://myServerURL")
}, 1)
and simply let that keep going, and pretty soon the entire server will be completely blocked off and / or crashed from the mass amount of constant connections from the same client.
So, although I am able to disconnect a user once it's attempted to connect (if I detect that it has already connected on the same IP address, for example), but how can I stop someone from simply sending in constant connections and / or commands like the above code? How can I completely block an entire IP address from opening any new connections, from the outset?
There are npm packages to help with rate-limiting, but I prefer to keep this out of the app server completely as they will still consume resources.
In practice I use Nginx as proxies to our api and configure these to rate-limit requests.
The following example will limit 10 requests per second based on user's ip:
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
Nginx is easy to get up and running, battle-tested and well documented.
If using Heroku, you can configure this pretty easily using a buildpack. Here is a demo repo to look at.
You can do this at your application if you must, but I'd recommend putting your server behind Nginx (or similar) and letting Nginx handle preventing these sorts of generic attacks.
https://www.nginx.com/blog/mitigating-ddos-attacks-with-nginx-and-nginx-plus/
That way, you can focus on building your application without having to reinvent the whole thing.

LDAP over TLS with ldap-client in node

I am fairly new to the concept of domains and am trying to implement LDAP over TLS in node. And I have been stuck with this issue for many days now. I am using ldap-client.
var LDAP = require('ldap-client');
var ldap = new LDAP({
validatecert: false, // Verify server certificate
...
}, function(err) {
// connected and ready
});
so with some research I came into conclusion that, if the field validatecert is to be set amount these values
LDAP.LDAP_OPT_X_TLS_NEVER = 0;
LDAP.LDAP_OPT_X_TLS_HARD = 1;
LDAP.LDAP_OPT_X_TLS_DEMAND = 2;
LDAP.LDAP_OPT_X_TLS_ALLOW = 3;
LDAP.LDAP_OPT_X_TLS_TRY = 4;
which was quoted under the section TLS in the library documentation
TLS can be used via the ldaps:// protocol string in the URI attribute on instantiation. If you want to eschew server certificate checking (if you have a self-signed cserver certificate, for example), you can set the verifycert attribute to LDAP.LDAP_OPT_X_TLS_NEVER, or one of the following values:
With which I could setup a secure connection.
I know that we need certificates for TLS connection to work. One is held by the server and another by the client (me).
My question is if I set the field to any of the said methods:
How am I to verify that my connection is secure ?
Where do I see the certificates or not see them at all ?
Do I have to manually generate certificates from the server and use them ?
Certificates are a means to help others verify that the entity presenting the certificate is indeed who it is claiming to be. Thus, when you connect to a server and server returns a certificate, then through that certificate you can be sure that server is indeed the server and not an imposter.
The power of certificate is due to the issuer (also called Certificate Authority or CA). If you trust the issuer, then you effectively trust the certificates issued by it. A list of prominent CAs is usually present in the OS itself, so getting a certificate and verification of that certificate is transparent to the application developer, especially when you are using libraries.
Taking your points one by one:
I know that we need certificates for TLS connection to work. One is held by the server and another by the client (me).
You didn't ask any question here, here is some general info. Usually server verification is all that's needed. In high security environments, client verification is done too and there you (i.e. the client) would need a certificate from a CA to verify yourself to the server. But, in most applications, server verification is sufficient.
It is similar to Normal Forms in RDBMS normalization. Even though you have Normal Forms as strict as 6NF, usually RDBMS's are normalized till 3NF.
How am I to verify that my connection is secure?
Generally, if you are using a well known library, (like curl or openLDAP) calling its secure connection methods is enough. It is very very unlikely that you called a function that the library claims to be secure but it turns out to be a farce.
To be sure though, you can look at your traffic with the server. Wireshark is often used for network traffic analysis.
Where do I see the certificates or not see them at all?
In most cases you don't see the certificates. All you do is tell your library how strict you want the verification to be. And then your library will take care of the rest - often throwing an exception or logging an error if there is some issue with the certificate.
If you are using a client certificate then you would have to keep it on the file system and point your library to it. It is generally a .pem file.
Do I have to manually generate certificates from the server and use them?
No. For server certs, it is the responsibility of the server to provide you with a valid cert. All you have to do is just check that the certificate sent by server is from an established CA - which, as told earlier, is generally a transparent step for the developer using the library.
In cases where you do not care much or in situations where you want to start coding and CA is yet to issue a certificate for you, you can program the server to provide its clients with a self-signed certificate and program the clients to keep the verification less strict.
A self-signed certificate has little value in terms of security. It is like server saying - 'Hey, I'm telling you that I'm the guy you want to talk to.' That clearly isn't enough. You want a third person (i.e. the CA), whom you fully trust, to confirm that that is the guy you wanted to talk to.

Websocket certificate for local network

I am having trouble with certificate when using websocket (WSS://).
What is working
For now, I've been using websocket with WEB_SOCKET_FORCE_FLASH = true and I had no issues with connecting to my websocket server.
What is not working
I am trying to turn that option off, to stop using flash plugin for connecting. Problem occurs when i try to connect my websocket client to server. WebSocket opening handshake was canceled message appears.
I can disable this message, by going to https://127.0.0.1:9999. My browser will show that "This Connection is Untrusted", and if I add an exception here, my websocket connection will start working without any problem from now on. But i CAN'T make every end user to do that, right?
Google groups with this idea
What I need?
Is there any way, to buy, or create some self-signed certificate, which I can use? The problem is also that, it doesn't have to be localhost/127.0.0.1 but also any other IP in local network. (like 192.168.0.100 etc). End user can change that IP whenever he likes to. He just needs to point on the PC where my desktop app/websocket server is running.
What have I tried?
I sure tried to find my answer in google, browsing tons of forums, sites, and even few questions and all answers here on stack overflow.
I also tried not using certificate at all, but my page is on https:// so connection using ws:// is impossible.
Code
I know, code is usually obligatory, but I actually got my websocket client/server working, but the issue is certificate, so i hope you can forgive me lack of code.
missing info?
Do i need to provide any more information? I am willing to make multiple edits if needed.
While the current certificate system is kind of broken it is fortunately not broken enough to allow what you want. What you expect to get based on your description is a certificate for an IP addresses (bad idea anyway) which you don't even own fully (you cannot claim to be the owner of 127.0.0.1 or similar addresses) which then will be accepted by every browser without the need to add a manual exception by the user.

Can I encrypt Node.js TCP traffic with TLS so it's impossible to read?

So I currently have a node.js app that reads my website user ips from a file and using geoip places a dot in a map for each visitor location.
Problem is, everytime a new visitor comes the message sent through the websocket can be seen by the client if he inspects traffic with wireshark or fiddler.
Obviously displaying user ips is out of the question, so I am wondering if using TLS would be enough to make this information unreadable or impossible to debug from the javascript code.
Thanks
The information is sent to the user's browser. The browser must be able to decode it to be able to work with it. The browser also incidentally offers debugging tools which allow the user to inspect everything that's going on. Ergo, the user is able to inspect anything and everything that the browser can. No, what you want is not possible. If the information is confidential, never send it to any client in the first place.
It will make it more-or-less impossible to sniff the data in transit.
It does nothing to stop people taking your JS and tweaking it slightly to log the data after the browser has received it.
You can't hide data you send to the browser from the person who controls the browser.
The biggest question is why are you sending the IP and the position to the browser? To place the marker on the map, you just need the position.
If you need to distinct the users by IP address on the client side, you could write an own hashing algorithm which concats the ip with a predefined string(secret). So the identifier is always the same for the same IP, but the IP is not reconstructable without the corresponding secret.
TLS helps against traffic snipping by 3rd party attackers. If normal users can access sensitive information, then TLS worths nothing. It is called Transport Layer Security for a good reason.

Categories

Resources