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

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).

Related

two way security (multi-protocol)

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.

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.

Securely connecting two node.js servers

I am hosting an app on Nodejitsu, and I want that app to turn pages to pdf with wkhtmltopdf, which is a binary. Alas I'm not on a big enough plan with Nodejitsu to get ssh access to install wkhtmltopdf.
What I want to do is host the pdf converter on AWS ec2. But I am unsure of a good way to connect the two node.js servers securely.
Also then when the two servers are connected, what would be the most efficient way to transfer files between these two servers.
Is there concrete design patterns for this?
It kind of depends what you need your security for, and how much you need. So I assume you have some data on your nodejitsu server and want to send that (as html) to Amazon, and receive it back (as pdf) from amazon to nodejitsu, and you want:
nobody to be able to read your document in between
nobody to tamper with your document in between
First, realise that anyone with the right access to nodejitsu or amazon (either an employee or a hacker) will be able to see your data anyways (and probably anyone with access to your database provider as well). The chances for a data leak somewhere there are imho massively larger than someone listening in / tampering on the connection in between (especially if you host both in the US, or (another) country whose government you trust (note that if the US government wants access to your data either the nodejitsu or the amazon servers are physically in the US, they will get it anyways). But, the thing is, barring some major internet disruption, the connection between nodejisu and amazon will not run through shady providers or open wifi networks.
Once you've decided you still want / need the extra layer of security (and complexity), I would say: choose the easy route. No https, no certificates, no asymmetric encryption. Just choose a shared secret (a random password, the longer the better), and just AES encrypt the data before sending it, and at the other end AES decrypt it (using the built in node crypt module). Just send your (encrypted) documents over http, and you're done. You don't even need any authorisation layer: anything received that doesn't encrypt to a valid document, can be discarded.
It is true that https would prevent some other attacks (chiefly that the shared secret probably is somewhere in your code, so also on your local machine (and github) and with asymmetric encryption you only need to store the public key in your code. But still, it will save you a lot of headaches!

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