WebSocket errors when using TLS (but not without) - javascript

I have a web application that uses WebSockets to communicate between browser and server. When serving as ws, everything works as intended. If I change the protocol to wss, things mostly work as expected (the majority of messages passed from client to server, or vice versa, are received), but I occasionally one of the following errors in the Chrome console:
"Could not decode a text frame as UTF-8."
or
"Invalid frame header"
...at which point Chrome releases the connection.
I have observed this both when serving wss directly from the server (runs on .NET, uses SuperWebSocket), and in a configuration where the server uses ws and Apache's mod_proxy_wstunnel to reverse proxy to this using the wss protocol. I have also set up a simple "echo" server under the same Apache configuration, and don't observe the issue; this leads me to believe there's something funny about the data we're passing to the SuperWebSocket API. (The messages which cause the error are valid UTF-8, and again, don't see this issue when serving over ws.)
I'm at a loss for how a protocol change would cause such an issue to occur, which leads me to my question:
Are there cases where a WebSocket frame might be valid when sent without TLS but would become corrupted when sent with TLS?

Are there cases where a WebSocket frame might be valid when sent without TLS but would become corrupted when sent with TLS?
No, wss:// is the same as ws:// only that it is not using plain TCP but TCP+TLS. The WebSockets protocol itself is not aware if it is running inside a plain TCP connection or a TLS protected TCP connection. This is similar to https:// vs. http://.
But a TLS connection is more sensible to data corruption. That is if some man in the middle modifies the packets properly simple ws:// will not notice while wss:// will croak because the modification of the packet was detected. But you should get the error then at the connection level (i.e. connection broke or similar) and not at the WebSockets level like in your case (invalid frame header).
I have no idea what you are running as a WebSockets backend but I would suggest that the problem lies there. Because of the additional TLS layer wss:// might behave slightly different regarding timing and buffering of data inside the server so there might be a race conditions which happens more likely when wss:// is in use compared to ws://.

Related

Validate WebSocket data

I have a WebSocket server written in javascript and send data to it from my CSharp application. Now how can I make sure that these are correct? I thought I could do something with hash values but I don't know how to do that. Does anyone have an idea or code example?
The first thing to understand is the types of WebSocket protocol/transports. WebSocket ws:// transport is basically unusable in terms of security as it uses HTTP. The wss:// protocol establishes a secure connection over TCP/HTTPS. The wss protocol, therefore, protects against man-in-the-middle attacks.
There is multiple methods to authenticate a user when setting up a WebSocket connection, and none are perfect. Since the standard WebSocket usage prevents additional headers from being set such as custom authentication headers, tried and true methods that would be used in a standard HTTPS request to verify the validity of a client can't be used.
The link here outlines some common methods to keep the client and server in sync while setting up a WebSocket connection, and still add some security so the server can keep track of what clients are opening WebSocket connections. There are a lot of workarounds listed for the server to safely receive sensitive, authentication data from the client.

Cross browser support for Websockets in ActiveMQ

It seems clear that Apollo has support for CORS in their websockets protocol, but I can find nothing comparable in ActiveMQ. In Apollo you can add the parameter "cors_origin" to the connector description, but I can find nothing comparable in ActiveMQ's documentation. I've tried the Apollo parameter but I'm still getting connection refused errors.
I'm attempting to use the Paho Mqtt javascript client to connect. The Go clients I've written work fine over both tcp and websockets, but I've had no luck getting the js client to work.
I'm pretty sure the problem is CORS. Any ideas on how to configure ActiveMQ?
My problem with the refused connections had nothing to do with CORS. It was an authentication problem with the ActiveMQ broker (my bug, now fixed).
However, it is interesting to node that ActiveMQ appears to completely ignore the websockets "Origin" header from the browser. In other words, it will accept connections from any host (including localhost). Apollo appears to behave differently with specific CORS configuration.

Proxy blocking websockets? How to get round

I have a websocket server running written in Python, (from https://github.com/opiate/SimpleWebSocketServer), and when I try to connect to it from my house, it works fine. However, when I try to connect to it from school, where there is a web proxy in place, it fails to connect with the error "undefined".
I believe that it is the proxy that is stopping the connection, but am not sure how to test to see if it definitely is. How can I test this, and if it is the proxy, how can I get round this?
Thanks
Many proxy servers replace the headers of HTTP requests with their own. They will remove any headers they don't understand, so when the proxy doesn't support websocket yet it will prevent any websocket handshake from working.
As a workaround you can get a TLS certificate for your website and use https and wss. This encrypts the headers and thus prevents the proxy from messing with them.
By the way: You should support TLS anyway. In todays world you no longer need a good reason to use encryption, you need a good reason not to.

Connect two socket.io clients together (Establish a socket to socket, cross browser connection)

I'd like to know if there's any way to establish a P2P connection between two browsers using socket.io-client (but I'm willing to use anything else that may do the trick).
Both browsers are currently connected to a node.js app serving HTTP requests with Express, which stores both clients's IP addresses (and ports when running locally). What I'd like to do is add a third connection that links both clients (let's call them A and B) directly, so that messages/data will go straight from one client to another, without transiting through the node.js server.
Is that feasible? If so, how?
So far, I've tried connecting the two clients (let's call them A and B) with the following code:
Client A:
A_to_server_socket = io();
A_to_server_socket.on('p2p', function(address_B){
A_to_B_socket = io(address_B); // Instantiates a new socket
A_to_B_socket.on('connect', function() {
console.log('Connected!');
});
});
I'm not sure about the code for client B. However I've tried:
repeat the above code for B, using B's own address (to override the default of connecting to the server)
repeat the above code for B, this time using A's address
having B_to_server_socket listen for a new connect event
However regardless of B's code, when running A's code I'm confronted with a "Cross-Origin Request blocked" error on Firefox, or "Failed to load resource: net::ERR_CONNECTION_REFUSED" followed by "net::ERR_CONNECTION_REFUSED" on Chrome.
Any hints towards a solution, or insights for better understanding the problem and how sockets work would be most welcome.
I'll try to summarize my comments into an answer.
In TCP, a connection is made when one endpoint A connects to another endpoint B. To connect to endpoint B, that host must be "listening" for incoming connections originating from other hosts. In a typical web request, the browser establishes a TCP connection to the web server and this works because the web server is listening for incoming requests on a specific port and when one of those requests comes in, it accepts the incoming request to establish an active TCP connection. So, you must have one side initiating the request and another side listening for the request.
For various security reasons, browsers themselves don't "listen" for incoming connections so you can't connect directly to them. They only allow you to connect outbound to some other listening agent on the internet. So, if a browser never listens for an incoming webSocket connection, then you can't establish a true peer-to-peer (e.g. browser-to-browser) webSocket connection.
Furthermore, TCP is designed so that you can't have two browsers both connect to a common server and then somehow have that server connect up their pipelines such that the two browser are now just wired directly to each other. TCP just doesn't work that way. It is possible to have an agent in the middle forwarding packets from one client to another via a separate connection to each (that's how Chat applications generally work), but the agent in the middle can't simply plug the two TCP connections together such that the packets go directly from one client to the other (and no longer go through the server) as a fireman would connect two firehoses. TCP just doens't work that way. It might be possible to have some complicated scheme that involved rewriting packet headers to a packet sent from endPoint A was forwarded to endPoint B and looked like it came from the server instead, but that still involves the server as the middleman or proxy.
The usual way to solve this problem is to just let each browser connect to a common server and have the server act as the middleman or traffic cop, forwarding packets from one browser to another.
Existing P2P applications (outside of browsers) work by having each client actually listen for incoming connections (act like a server) so that another client can connect directly to them. P2P itself is more complicated than this because one needs to have a means of discovering an IP address to connect to (since clients typically aren't in DNS) and often there are firewalls in the way that need some cooperation between the two ends in order to make the firewall allow the incoming connection. But, alas, this capability of listening for an incoming connection is not something a browser from plain javascript will allow you to do.
There is no something like "connection between two browsers using socket.io-client."
But there is "Both browsers are connected to a node.js app serving HTTP requests with Express, which keeps track of both clients's IP addresses (and ports when running locally)."
If you want to have P2P connection between two browser, following may be a way to do so.
when you get client A connection, join to a room "P2P"
when you get client B connection, join to a room "P2P"
to exchange between client A and client B, use
socket.broadcast.to('P2P').emit("message", "Good Morning");
Hope this may help.

Firefox OS TCPSocket API : SSL received a record that exceeded the maximum permissible length

Is it possible to turn off SSL cert verification in Firefox OS? I have Geeksphone dev preview and try to make IMAP client via TCPSocket API, but server cert is somehow invalid. I got this error:
SSL received a record that exceeded the maximum permissible length.
(Error Code: ssl_error_rx_record_too_long)
My TCPSocket initializacion is as follows
var TCPSocket = navigator.mozTCPSocket.open(
"mbp.telekom.de",
993,
{useSSL:'starttls'}
);
When I try to connect to GMail or another account, everything works OK.
Is this really server cert error or is it something else?
Thanks
Turning off the certificate verification is generally a bad idea and unlikely to help. The error says ssl_error_rx_record_too_long, and record that is too long is just too long, whether you choose to accept any certificate or not. This type of error tends to be caused by a record that is "too long for SSL/TLS", that is, some message that isn't valid SSL/TLS at all.
There are a few other problems here.
According to the documentation, TCPSocket takes a boolean for its useSSL parameter, not a string. It would seem fair to assume that somewhere in the code, there's an if (useSSL) {...}, so 'starttls' in your configuration counts as true.
Port 993 tends to be usable for IMAP over SSL (after an initial connection via SSL), not IMAP+STARTTLS on port 143 (where the same socket is upgraded to SSL/TLS after an initial plain-text connection).
The server at mbp.telekom.de doesn't accept SSL/TLS initial connections (like most IMAP servers would on that port), but accepts plain text IMAP connections upgradable to SSL/TLS via STARTTLS (which it should do on port 143 instead). This is likely to be a problem with the server configuration. This also explain why your connection works with imap.gmail.com (since it does support normal SSL/TLS connection that don't use STARTTLS on port 993, and since your {useSSL:'starttls'} in fact means {useSSL:true}).
You could in principle implement your IMAP client to upgrade the connection to SSL/TLS after using the STARTTLS command, but you'd need to be able to upgrade the same socket to SSL/TLS. I can't see anything in the TCPSocket documentation that would allow this (in the same way as SSLSocketFactory.createSocket(Socket, ...) does in Java, for example).
EDIT:
After a quick look at the TCPSocket.js source code, it seems that it does support starttls indeed, but this only makes sense with the undocumented upgradeToSecure method.
You might be able to implement IMAP+STARTTLS this way: initiate a plain IMAP connection, and then upgrade to SSL/TLS with the STARTTLS command, as described in RFC 2595. This is normally done on port 143, but since your server is (rather incorrectly) configured for this on port 993, it should work there too.
That's not a certificate error, that's an SSL protocol error. SSL packages data into 'frames' or 'records'. (pretty much packets, but at the SSL level rather than the socket level). There is a maximum length for these frames (16kb, I believe), and the server sent a frame longer than that. I couldn't tell you why: but maybe their certificate is too big and their SSL lib has bugs.

Categories