A chat with nowjs or socket.io is one of the easiest exercises you can perform with them. I want to implement a multi-room chat (with a non-fixed number of rooms and logged users), using nowjs' Group objects.
I've not worked with WebSockets directly, yet, and I want to know what security concerns are there. For example, how often do I have to check for authentication?
Is it possible for an attacker to "hijack" a socket.io connection and how can I prevent it?
What other security traps are there to be concerned?
Man-in-the-middle is certainly a consideration. The biggest security issue, though, would be XSS.
This useful SO thread suggests:
socket.io 0.8 has referrer verification built in
if chat is from known origin, block superfluous connections at the firewall
This very informative article suggests:
don't trust the client
use SSL encryption
check the origin
prevent XSS (sanitize client input!)
don't assume it's a browser
This useful thread says to set secure:true on socket.io.connect(...)
I'd recommend taking all those suggestions :)
Related
Why am I using websockets?
I'm working on routing all my HTTPS requests via a WebSocket, because my app has a chat feature and I need to keep the WebSocket open when the app is running, so why not just route all the requests through it.
My problem.
This turned out to be easier said that done. Should I use the same Access token & refresh token to verify client authentication. Or should I just verify it when the connection opens and then trust it for as long as it's open. So here are my questions:
Is wss(Web socket secure) enough to stop man in the middle attacks?
Should I generate a ticket sort of mechanism for every WebSocket connection, that lasts 2 - 10 minutes and then disconnect and ask the client to reconnect?
Or should I have a Access Token with every request from the client.
How to I make sure that when the server sends the data it is going to the right client.
Should I just end to end encrypt all the payloads to avoid a lot of problems?
Or should I just verify it when the connection opens and then trust it for as long as it's open.
That is fine as long as the connection is over a trusted channel, e.g. ssl/tls.
Is wss(Web socket secure) enough to stop man in the middle attacks?
Yes. Wss is simply ws over ssl/tls.
Should I generate a ticket sort of mechanism for every WebSocket connection, that lasts 2 - 10 minutes and then disconnect and ask the client to reconnect?
I'm not sure why would you do that. On the contrary, with chat-like app you want to keep the connection open as long as possible. Although I advice implementing ping calls on the client side and timeouts on the server side. With such approach you can require action on the client side every say 30s.
Or should I have a Access Token with every request from the client.
Not necessary. With ssl/tls you can authenticate the entire connection once and just remember on the server side that is authenticated. Tokens are used with the classical HTTP because it is easier to scale horizontally such app, e.g. it doesn't matter which server the connection goes to, you can even switch servers between calls and that won't affect auth. But with chat-like app (or any app that requires bidirectional communication) the connection has to be persistent to begin with, and thus tokens introduce unnecessary overhead.
How to I make sure that when the server sends the data it is going to the right client.
I'm not sure what you mean by that. That's pretty much what tcp + ssl/tls guarantees anyway. It is the same for any other protocol over secure tcp. Or do you mean at the app level? Well you have to match a user with a corresponding connection(s) once authenticated. The server has to track this.
Should I just end to end encrypt all the payloads to avoid a lot of problems?
What problems? E2E encryption serves very different purpose: it guarantees that you, a.k.a. the server, is unable to read messages. It guarantess high level of privacy, so that even the server cannot read messages, only peers. And so this is a business decision, not technical or security decision. Do you want to have full control over conversations? Then obviously you can't go with E2E. If on the other hand you want to give the highest level of privacy to your users then it is a good (if not mandatory) approach. Note that full featured E2E is inherently more difficult to implement than non-E2E.
I need to keep the WebSocket open when the app is running, so why not just route all the requests through it.
That is an interesting approach. I myself am thinking about doing that (and most likely will try it out). The advantage is that entire communication goes through a single protocol which is easier to debug. Another advantage is that with a proper protocol you can achieve higher performance. The disadvantage is that the classical HTTP is well understood, there are lots of tools and subprotocols (e.g. REST) covering it. Security, binary streaming (e.g. file serving), etc. are often managed out of the box. So it feels a bit like reinventing the wheel. Either way, I wish you good luck with that, hopefuly you can come back to us and tell us how it went.
I have website X which runs a websocket server (socket.io, all based on node.js) and feeds clients with live data.
Now, competitor Y started connecting to our websocket server and straight out stealing data from it, displaying it also live on their website.
I've made numerous attempts at blocking their IPs, but they'll just keep changing it within a matter of minutes. (All kinds of AWS / cloud hosting providers). I check the referrer header, user-agent, accept-language, pretty much anything but all of that is spoofable and they do this already.
The websocket connections are proxied through nginx, if that helps.
What would you do?
Client X (the website) or client Y (the competitor) is meaningless. It's just a client. There is no reliable (i.e. impossible to hack) way to distinguish them unless you restrict IPs (which you already know that it fails). That's because client Y can easily construct a HTTP request/Websocket connection from scratch so that it looks like client X. And there's more: going down that road might be a waste of time and other resources. Eventually you will be hacked. The question is: which company has more resources to withstand this fight? :)
Authentication doesn't change much. Because client Y can authenticate as well. It's just instead of fighting with IPs you fight with user credentials. It might be easier though. You should try it.
So IMHO all in all what you end up with is constant monitoring and reactions. If they break law/agreements then you should sue them. If they don't then you can try this guerilla warfare. You might win eventually, who knows.
You could verify the Origin header in the websocket request matches the origin of your clients. However, I'm not sure if it's possible to fake this header at all.
An Authentication subsystem is a well-known solution to this problem to a large degree.
I am looking to implement web (angular) and iPhone apps using WebSockets to communicate with our server. In the past using HTTP requests we have used hashes using the request data, url, timestamp etc to authenticate and secure the requests.
As far as I am aware we can't send headers with WebSockets requests therefore I am wondering how I can secure each request.
Does anyone have any ideas or good practices?
To secure your messages, use WebSockets over SSL/TLS (wss:// instead of ws://). Don't roll your own crypto.
Concerning authentication. The big difference between HTTP and WebSockets is that HTTP is a stateless protocol and WebSockets is not.
With HTTP you have to send headers (cookies, tokens, whatever) with each request. With WebSockets you establish a connection. In the first interactions you can authenticate the client and for the remainder of the connection you know the client is authenticated.
The people at Heroku have described a pattern where the client authenticates using HTTP, gets a ticket and then sends that ticket as a first message over the WebSocket connection. See https://devcenter.heroku.com/articles/websocket-security
I agree with the SSL/TLS wss:// connection. Always use encrypted traffic. There are several ways to implement a authentication. See here:
http://simplyautomationized.blogspot.com/2015/09/5-ways-to-secure-websocket-rpi.html
Most to all examples use python or nodejs and are directed for the Raspberry Pi but the general concepts are good ideas to consider. There are links in the post to a SocketRocket helper library that allows you to insert authentication into the auth header (SocketShuttle).
Having secure communication with server includes authenticating both parties to each other. If you need to channel different users with different authentication credentials through one communication channel (which is a rare idea nowadays), you'll need separate authentication. Otherwise, you just need to come up with key distribution scheme (so that your apps know public keys of your server and your server has a protocol of getting acquanted to public keys of clients, there are plenty of patterns for this).
To do that, there is a choice gradient a bit wider than SSL or your own crypto (try to avoid writing your own crypto at any cost).
For webserver-to-browser part of stack, SSL is your only choice, however it shouldn't be considered as a good safety measure, each year unfolds more and more vulnerabilities, cipher degradation cases and trust problems. It carries 20 years of baggage of bad engineering decisions and urgent fixes, so if you can get something better - it's worth doing so. Still, it's much better than nothing for the regular webs.
In your mobile app you could easily use one of a number of cryptographic libraries providing secure session messaging with server with significantly higher security guarantees, no reliance:
https://github.com/mochtu/libsodium-ios, libsodium-ios, an ios wrapper for NaCl, one of the best modern cryptographic libraries, which has lots of novel implementations to ECC cryptography, is highly praised in academic circles and written by a madman keen to have best performance under all circumstances (in short: I adore it :) ).
Themis, a project I'm a contributor in, we have very ObjC-friendly iOS version of our library, and a handy tutorial on doing secure traffic over websockets in iOS: https://www.cossacklabs.com/building-secure-chat
You should secure your connection with SSL/TLS and use https over http and wss over ws. For having auhentication/authorization, you can add query params to the websocket connections and also add something like username/passwprd.
For instanse :
wss://example.com/path?username=password=anotherParam=99ace112-dd56-427e-ba3d-9dd23e9c7551
yes, in js you cant add your arbitrary header, but you are allowed to add protocols and Sec-WebSocket-Protocol header to your webocket connections and on the server-side authenticate/authorize users based on websocket protocols
I'm working on a network program and I don't want anyone to know what kind of information is being passed when they sniff the network. Would using TLS achieve this? My main reason is that I want to keep the protocol I'm using to myself for now. If not please tell me if there is anything that can achieve my goal.
It depends on a lot of things, e.g. what your exact threat model is, and how much information leakage you can tolerate.
For TLS to provide adequate protection, these assumptions must be true:
Obviously, you should use a correct implementation, otherwise, if for instance, you are using SecureTransport from iOS 7.0.4, all bets are off.
You should enforce a minimum version requirement and only support secure ciphersuites. If you allow downgrade to SSLv2, you are setting yourself up for problems.
You check for validity of the server public key. You'd be surprised how many client apps skip this.
You use client certificates to authenticate the client, as well as the server, otherwise, it is possible to write a phony client that talks to your TLS server and reverse engineer your protocol. (You can also authenticate the client early in the protocol lifecycle using other means, but that part of your protocol would not be safe).
You keep the private keys secure.
(If you are using X509 certificates and trust chains:) Certificate authorities that you trust do what they are supposed to do, i.e. not sign certificates in your name for others.
You will still leak some packet length and timing information that you hope would not be complete enough for the reverse engineer.
The attacker does not control your client or server or have access to the binaries on any side. If, like an iPhone app, you are giving away the client binary, you have already lost.
Your higher level protocol cannot be tricked into say, redirecting to another server blindly, or lose its mind and do some other crazy thing when the client secure channel is interrupted. This can be hard to notice at times and depends on many other factors.
Something else I have probably missed here.
Would TLS prevent others reverse engineer my protocol?
Probably not. Pentesters do it all the time. They use something like Burp Suite to proxy the connection and watch all the web requests.
If not please tell me if there is anything that can achieve my goal.
Common practice is: if you don't want it stolen, copied, pilfered, abused, etc, then you don't put it on a client. So all sensitive code and data goes on a server you control. Since the client gets to see the request, you have to remove all sensitive information from it.
I am creating a TCP based game server for iOS, it involves registration and login.
Users will be stored as a collection in MongoDB.
when login is done, I generate a unique session id - How ?
I wanted to know what all data remains with node server and what can be stored in db.
data like session tokens, or collection of sockets if I am maintaining a persistent connection etc.
Node.JS does not have any sessions by default. In fact, there is a plug-in for managing sessions with MongoDB.
It's not clear that you really need sessions however. If you're opening a direct socket with socket.io, that is a defacto session.
Node.js itself does not manage sessions for you. It simply exposes an API to underlying unix facilities for Socket communication. HTTP in it self is a stateless protocol and does not have sessions either. SSH on the other hand is a stateful protocol, but I do not think either one would be good for you.
Creating a uniuqe ID is really simple, all you need to do is hash some data about the user. Their SHA(IP address + time + username). See: http://nodejs.org/api/crypto.html
One approach a lot of applications take is to create their own protocol and send messages using that. You will have to handle a lot of cases with that. And I myself have never dealt with mobile where you have serious connectivity challenges and caching requirements that are not a big problem on desktops.
To solve these problem, founder of Scribd started a company called Parse which should make it much easier for your to do things. Have a look at their website: https://parse.com/.
If you want to do some authentication however, have a look at Everyauth, it provides a lot of that for you. You can find it here: https://github.com/bnoguchi/everyauth/.