Win a copy of Kotlin in Action this week in the Kotlin forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic

best way to secure communication for 'p2p' like application?  RSS feed

 
Dan Peters
Greenhorn
Posts: 10
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Greetings!

Be forewarned, this may get lengthy, so thanks in advance for reading!

Here's the deal. I have a project I've come back to recently to add some features:

https://sourceforge.net/projects/loki-render/

First a bit of background on how Loki works (with some programming details) so my question later makes sense:

In short, it's a job batch system specifically for rendering images for 3D rendering software called Blender. Concept is simple: run the 'master' somewhere, then as many 'grunts' (slaves) on as many computers as you want. Flow is basically:

1. user creates a job on the master, which is simply a list of images to render
2. each grunt is passed an IP address and port, which it uses to request a connection on the master's 'listen' port, and then establish it's own socket connection.
3. the master passes files to the grunts they need to accomplish their render task
4. grunts pass the finished images back to the master

It's also good to point out that the application is distributed from SF as a monolithic jar file - when the app launches, the user is asked what role it will fill on the computer: master or grunt.

Now on to some current musings on security as the application is now, (if I'm missing something or have something wrong, please let me know):

*all information is sent in the clear, no encryption - this means the data is potentially open to others to read, both the project files sent to the grunts, as well as the finished images sent back to the master
*there's no authentication of master, so someone could potentially setup a fake master, but that would mean they'd need to spoof the master's ip address, or otherwise redirect traffic from the grunt to their system
*there's no authentication of the grunts, which means someone could potentially setup a fake grunt - that's easier since it's just a matter of connecting to the master
*in the two cases above of fake master or grunt, if they send bad data in the socket then that could certainly crash the application, or they can act like their supposed to and just copy data
*potential man-in-the-middle attack - insert in the middle to copy communication and then just pass it on.

Typically my application has been used on LANs and other fairly trustworthy networks. It used to exclusively use an 'auto-discover' option which excluded using across routers, but now I've added a 'specify master's IP' option. Users are now doing cool things like running a ton of grunts in AWS and having them connect to the master on their desktop. Loki doesn't currently pass any command lines directly to the grunts, so a malicious user can't inject commands to the grunts which is good, but the data still is open on the Internet, which I don't like.

I'd now like to add a feature that allows the user to specify a python script that they'd like to run on the grunts with the render job. For this feature I think I definitely need to tighten up security to avoid the potential of malicious scripts being injected into the tasks that are sent out to the grunts.

So the question is what kind of security is needed, and how best to do it?

Here are some current thoughts:
*To begin with, I first thought of a secret shared key for socket communication - this will certainly provide encryption between master/grunts, but all communication shares one key, and this key by necessity needs to be in the jar file, which anyone can extract, thus anyone who wants to read a master/grunt stream can get the key and read it, so this solution seems nearly worthless.
*SSL - This is the one I've been thinking about the most - Loki communication can in a way, be regarded as peer to peer communication - where the master and grunts run is somewhat mobile, so the traditional SSL approach of having a trusted server that has a signed certificate doesn't really work here, nor can each grunt be verified as authentic from the master side, but what SSL can still offer is a unique secret key that is used between the master and each grunt which connects, which is still valuable.

So I started setting up with SSL, created the server key, it's public certificate etc. But then I realized that since Loki is monolithic for both master and grunt, the server's private key and public certificate would both need to be in the jar file, which anyone can then take out and inspect. This renders the whole authentication portion of SSL useless, right? SSL's authentication mechanism of the server only works if the server's key is kept private, AND the client has a way to verify the server's certificate, neither of which seem possible with Loki.

This leads to one of my main questions for the post:

In this particular case, would it make more sense to, on the client side, disable certificate validation, like mentioned in option 2 here:

http://stackoverflow.com/questions/2893819/telling-java-to-accept-self-signed-ssl-certificate

There's all these dire warnings about doing so, and in a regular context of, say a webserver, authenticating with the correct server is vital, but with the situation with Loki, it seems like disabling certificate validation is reasonable, since there's no good way to verify master and client anyway.

As I see it, using SSL without certificate validation, I'll still get a unique encryption key for each grunt's communication with a master. This will at least guarantee that no one can read or inject data into an existing stream, though it doesn't preclude a false grunt connecting to the master (easiest) or a false master being setup and having the grunts redirected to it (a little more difficult since it would require re-routing to a spoofed IP address, as I understand it)

Am I missing something here? Are there any better approaches to this?

Thanks again for reading. Any thoughts, suggestions, etc are welcome!
 
Henry Wong
author
Sheriff
Posts: 23283
125
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Dan Peters wrote:
*To begin with, I first thought of a secret shared key for socket communication - this will certainly provide encryption between master/grunts, but all communication shares one key, and this key by necessity needs to be in the jar file, which anyone can extract, thus anyone who wants to read a master/grunt stream can get the key and read it, so this solution seems nearly worthless.


You kinda gave up on encryption way too early. After all, how do you think SSL does it? Wouldn't it also have the same issue when it does encryption? And since it doesn't, aren't you interested on how it works?

In my opinion, the easiest way to solve this problem is to use an asymmetric encryption algorithm like RSA. With that algorithm, the receiver can randomly generate a key pair, and sends one of those keys (in the clear) to the sender. The sender then encrypts the payload with the key and sends it to the receiver. The receiver can then decrypt the payload using the other key in the pair. Since it is not possible to decrypt using the same key to encrypt, nor is it possible to figure out the other key in the pair (given one key), the payload should be secure.

Alternative, if you really want to use a symmetric key algorithm, Java does provide access to Diffie Hellman. I personally never used it, because I use asymmetric keys -- but basically, the two sides generate random numbers, which is then used to generate interim keys. These keys are exchanged -- and the algorithm is designed that, with both sets of keys, and only *one* of the original random numbers, they arrive at the same key. In other words, the two sides come to an agreement on the key, and anyone seeing the communication, won't have enough information to figure out the agreed upon key.

Henry
 
Henry Wong
author
Sheriff
Posts: 23283
125
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
And BTW...

Dan Peters wrote:
*To begin with, I first thought of a secret shared key for socket communication - this will certainly provide encryption between master/grunts, but all communication shares one key, and this key by necessity needs to be in the jar file, which anyone can extract, thus anyone who wants to read a master/grunt stream can get the key and read it, so this solution seems nearly worthless.


If you can't secure the jar file, then nothing will work perfectly. What's preventing someone from decompiling your code, and adding code to steal stuff, after all the encryption/authentication is done? You need to secure the application itself -- and if you can't, then you need to not put the application at that location (such as with a web app). This is a design issue, that you need to work out first. Adding encryption/authentication is not going to completely work here.

Henry
 
Dan Peters
Greenhorn
Posts: 10
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Henry Wong wrote:
Dan Peters wrote:
*To begin with, I first thought of a secret shared key for socket communication - this will certainly provide encryption between master/grunts, but all communication shares one key, and this key by necessity needs to be in the jar file, which anyone can extract, thus anyone who wants to read a master/grunt stream can get the key and read it, so this solution seems nearly worthless.


You kinda gave up on encryption way too early. After all, how do you think SSL does it? Wouldn't it also have the same issue when it does encryption? And since it doesn't, aren't you interested on how it works?


Oh no, I'm not giving up on encryption in general, I was just saying that the specific case of having a single shared key for all sessions between master and grunts is a bad idea since anyone can pull that out of the jar and then have access to all the communications; it would be like the one magic key for reading everything. Also, of course SSL is using encryption:-)

Henry Wong wrote:
In my opinion, the easiest way to solve this problem is to use an asymmetric encryption algorithm like RSA. With that algorithm, the receiver can randomly generate a key pair, and sends one of those keys (in the clear) to the sender. The sender then encrypts the payload with the key and sends it to the receiver. The receiver can then decrypt the payload using the other key in the pair. Since it is not possible to decrypt using the same key to encrypt, nor is it possible to figure out the other key in the pair (given one key), the payload should be secure.

Generating a random key pair for each master/grunt session would be great. This is what I was getting at in regards to SSL, thinking that SSL uses the private/public key to share a random generated shared key for further communication, but maybe I've got it wrong.
 
Dan Peters
Greenhorn
Posts: 10
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Henry Wong wrote:And BTW...

Dan Peters wrote:
*To begin with, I first thought of a secret shared key for socket communication - this will certainly provide encryption between master/grunts, but all communication shares one key, and this key by necessity needs to be in the jar file, which anyone can extract, thus anyone who wants to read a master/grunt stream can get the key and read it, so this solution seems nearly worthless.


If you can't secure the jar file, then nothing will work perfectly. What's preventing someone from decompiling your code, and adding code to steal stuff, after all the encryption/authentication is done? You need to secure the application itself -- and if you can't, then you need to not put the application at that location (such as with a web app). This is a design issue, that you need to work out first. Adding encryption/authentication is not going to completely work here.

Henry


Yep, it seems that's pretty much the challenge - since the jar file is openly distributed, all of it's contents are public and could be altered to capture data or whatever, and there's no point in trying to hide a private key in there either. It does seem though that establishing encrypted communication with a unique key for every master/client does guarantee that data is protected in transit across networks, but doesn't protect against exploitation of the running code.

It's like the 'who to trust' question - can the master or client that I'm connecting to be trusted? For example when using SSH, to connect to a new/untrusted host, it shows you the host fingerprint, which is derived from the host's public RSA key, and then it's up to the user to decide whether or not to trust the host. Or in this case it's a question of whether or not to trust the master or client on the other end, and perhaps another important question: how much does it matter?

I'll think through this some more. Thanks for your thoughts.
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!