two way security (multi-protocol) - node.js

I'm implementing an one-to-many multi-protocol server (+ clients) and I'd like to add 2-way security. Here's what I'd like to accomplish:
both client and server authenticate to each other in a secure way. there is no human interaction involved on the client side.
client's code checksum is validated on the server.
client's code may be written in an interpreted language (such as python or javascript), so I'd like to prevent the possibility to compromise the network after someone gains access to the client (this may be an overkill though, because my clients won't be executing anything on the server, just reporting the results of their actions)
How should I design the authentication flow? What techniques should I use/google for, or - on a lower level - what existing solutions could I try? (my prototype is written using node.js)

SSL can do authentication both ways. Out of the box, nothing special needed. One can even get the certificates for free (self-signed or from recognized CAs).
Client certificates can be used to distinguish clients if that's a need, similarly they can be used to prevent copies of clients that log in simultaneously.
What you fundamentally cannot do is prevent a smart malicious user from controlling a client in such a manner as that they reverse engineer how it interacts with the server and instead of running your intended client, run their own that still acts as if it is the real client but isn't.
The solution to the impossibility of trusting the client is to not let it do things that you have to trust it is running your code unaltered. That often means moving from a 2 tier model (heavy client - server) to a 3 tier model where the code that you want to run is kept on hardware you control, and only an (untrusted) user interfacing is pushed to the user controlled hardware.

Related

How to do authentication over web sockets?

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.

Client Server: How to make it more difficult for client to modify their source code

I have an imaginary program that I've distributed to dozens of clients which involve their home thermostats. The script performs two tasks:
When a request from my server is received, the script will modify the temperature of the user's thermostat to the designated temperature.
When a request from my server is received, the script will reply back the current set temperature of the thermostat.
The program being ran on the clients computer is programmed in a scripting language and is not compiled. The source code can be modified at any time and the new modified script can be re-ran at will.
I have three problems:
What changes can I make to the script running on the client's computer and/or the program running on my server such that I feel more confident that the user did not tamper with the source code of the script?
How can I be relatively sure that the user is running the most up-to-date version of my program?
Without using IP addresses, how can the client know a request came from the server and not another client?
I understand that code running on a client's PC is impossible to police. However I want to make it less trivial for someone to modify the source code of my script.
As you correctly point out, it's impossible to guarantee nobody modifies your source - or replaces your client with an entirely different one they write from scratch. It simply cannot be done and it's not even because your client is implemented as a script; binaries can be replaced/spoofed as well.
What changes can I make to the script running on the client's computer and/or the program running on my server such that I feel more confident that the user did not tamper with the source code of the script?
Make your script compute a cryptographically secure hash of its own source code and send that hash to the server. You'll know what the hash of your client's source code is and can make sure this is the same. This does not guarantee the client is not pretending to be running your source (they could compute the hash of your client and send it while running entirely other code) but this will prevent casual and/or accidental modifications to the script from working (i.e. it guarantees any spoofing is intentional).
How can I be relatively sure that the user is running the most up-to-date version of my program?
Include a version number in the client source code you distribute so you can guarantee each new version has a unique hash with almost 100% probability. Then, you can have a history of versions with corresponding client hashes.
Without using IP addresses, how can the client know a request came from the server and not another client?
This one you can actually do correctly. Have your server use its private key to sign the messages it sends, and have your client verify the signature using your server's public key (which the client source code can contain). Since only your server could possibly have signed the messages with the correct private key, the client can be confident that success with the corresponding public key means your server sent the message.
If it is a home thermostat, the whole architecture is likely wrong. Your server will not be able to connect to devices on your customers' home networks (or at least they will have to perform configuration that you should not expect to be done).
So in a better architecture, you have your service on the internet, to which your devices connect. Note that these connections can be long ones as well, not necessarily just the typical short-lived http connections.
The client software running on a device can be modified by your users arbitrarily, or they can make other clients, you cannot do much about this. In reality, unless this is very valuable for some reason, nobody will bother, especially in a commercial way, because any change to your api will break 3rd party clients. One option to still make client code harder to modify is obfuscation, but be aware that it is not really a security feature, but it does increase the necessary effort.
Checking the version of the client is straightforward, it can just be sent with requests. However, the usual way to achieve what I think you wanted is to version your API. You probably don't care about the exact version of the client, but you do care about which version of the service (the API) it supports. If that is your goal, look into API versioning.
Authenticating the server in this architecture is straightforward if communication uses TLS. With TLS (eg. https), server authentication is implicit. You still want to authenticate the client though, which can be done via the standard means, a username-password, tokens or a client certificate. When talking about devices, you might want to consider a device with a TPM chip so that it can securely hold secrets, but whether you need that depends on the exact scenario and your threat model (who will have physical access, what happens if they can impersonate other devices and so on).

How do you trust a client?

I am working on a game where the world simulation is performed on clients. These clients submit updated world state to a central server. That server then redistributes those changes to the rest of those clients. Simple.
The issue is, I want to protect against modified clients. That is, I want to prevent cheaters that modify variables or whatnot in the executable.
At first I thought I would use a public key/private key encryption scheme. All commands sent from the client would be encrypted and sent to the server. But I quickly realized that this doesn't offer any real protection against cheaters since they can still modify variables.
The only other solution I can think of is to store all variables in a file and to record a hash of it. Then the client can only update the server after the server verifies these hashes.
But then I realized that a cheater could just rewrite the network request to patch those hashes.
I don't know where to go from here.
What protocols can be put in place so that the server only accepts commands from trusted (i.e. known) code bases?
You don't have to be so pessimist. Do your best to avoid cheaters to modify your data. For example one of common ways is to inject a DLL to game process and modify data on memory. Most game trainers do it in this way. You can periodically check your process's loaded modules and exit if there is unknown module. You may think of game's internet connection. Well, do your best. Add encryption and some custom handshake algorithms to make it complex and hard for cheaters.
In general, there is a lot of things which you can do to make your game hard-to-cheat.

would TLS prevent others reverse engineer my protocol?

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.

TCP secured connection - only via my client

so I have this TCP connections between my server and client, and anyone can connect to my server. But I want to make sure that the client is really using MY client application and not just faking messages from a fake TCP client. What would be the ways to do that, check that the connection really is from my game client?
Thanks!
EDIT
If I'm gonna use TLS, can I solve that problem?
There will probably not be a complete solution to your problem, since whatever you do, the other party might always take your program, run it in a monitored environment, manipulate the runtime data and let it use its "secure" network protocol. Since the client application is in uncontrollable hands, you can never be sure that it is your own program.
Baby example: My application runs your application and plays back the data to your server, and forwards your response back to the application. How can you tell?
That said, it might be a very promising "99%" approach to use SSL and hardcode the client's private key into the application -- with some trickery you can try and make it hard to find (e.g. see how Skype does it). If you then also build integrity checks into your program that figure out whether anyone is manipulating the memory or debugging into your program, you can try and make it a bit harder for a potential adversary. (But note that you will always have to ship the private key with your application, so it isn't really safe from discovery.)
Others have suggested useful answers to your question, but I'm going to suggest another approach. Re-examine your requirements.
Ask yourself why you want to know the identity of the client program. Is it so that you can trust your client program more than you trust 3rd-party client programs?
If you need to trust the identity or integrity of software that you have already shipped to your customers, I claim your security model is broken. Once the software runs on a client's PC, you should assume it is evil, even if you originally wrote it.
Any status, any command, any data whatsoever that comes from the network must be checked before it is relied upon.
My default response is to use a challenge/response authentication.
After connection, send a random number from the server to the client
The client then computes, using a hash/key/.... a response message and returns that to the server
If the response matches the servers computation, your chances of authenticity are better. Note though that a reverse engineer of your client will leave this method open to fraud.
You could use a public/private key pair in order to verify that you are who you say you are.
http://en.wikipedia.org/wiki/RSA#Signing_messages

Resources