Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add easy encryption to HighLevelMultiplayer Api. #19110

Closed
Malkverbena opened this issue May 22, 2018 · 51 comments · Fixed by #35091
Closed

Add easy encryption to HighLevelMultiplayer Api. #19110

Malkverbena opened this issue May 22, 2018 · 51 comments · Fixed by #35091

Comments

@Malkverbena
Copy link

I was thinking of some important security features that are lacking in Godot. When you have an online business it is necessary to protect the data of your users and avoid cheating. In the gaming industry it's no different, especially for companies that move amounts of money.
Due to this, I think encryptions methods on network api would be very welcome.
This will not solve all the security issues but it sure is a big step.
These features should also attract more attention to the engine from companies of all sizes and more users to Godot.

My propose is add some encrypt method on the api.
Maybe something like:
host.set_encrypt_mode(key, settings)
get_tree().set_network_peer(host)

And if possible add support to WebSocket Security

@Zylann
Copy link
Contributor

Zylann commented May 22, 2018

Maybe that would also be needed for stuff as simple as an online leaderboard?

@raymoo
Copy link
Contributor

raymoo commented May 24, 2018

Why specifically leaderboards?

@Zylann
Copy link
Contributor

Zylann commented May 24, 2018

@raymoo I was just giving an example of use case for encryption, since a leaderboard needs some way to prevent hacking results using keys.

@raymoo
Copy link
Contributor

raymoo commented May 24, 2018

@Zylann I don't know what it means to hack results using keys

@Zylann
Copy link
Contributor

Zylann commented May 24, 2018

@raymoo sending a hash from the client with scores so that you can check if it's valid server-side by computing the hash again with the same algorithm and a private key. Godot has MD5 only so far though, but maybe it's not related to that issue actually...

@raymoo
Copy link
Contributor

raymoo commented May 24, 2018

@Zylann Makes sense, for a moment I thought the issue was to add some ssl-like layer under the multiplayer API.

@Malkverbena
Copy link
Author

SLL requires a public registry. I'm sure it's interesting for companies that leads online business, but too complicated to regular users. it's a good point to think about.
But I was thinking just to encrypt the data handled by godot's network_api with a key.
I think it's enough to strengthener a lot the Godot's security.

@akien-mga
Copy link
Member

CC @Faless @mhilbrunner

@Faless
Copy link
Collaborator

Faless commented May 25, 2018

Long story short, there are multiple ways to achieve encryption:

  • Implementing DTLS for UDP
  • Implement encryption via symmetric key (AES/whatever) as proposed.
  • ... (many more protocols)

None of them prevents cheaters, nor users to read the content of the data being transferred (but DTLS does protect from eyesdropper, while AES alone doesn't unless you also implement secure key exchange).

If you want to avoid cheaters, make the server authoritative (i.e. do not trust any data coming from clients), there is no other way (at least to my knowledge).

If you want to protect data from the users, don't send it. If you do, no matter what you do, the users will be able to read it (otherwise the application on their end wouldn't either).

Both those options are viable, and PRs are welcome, sadly, I find myself with very little time between work, GSoC, and other personal obligations.

@Faless Faless changed the title Security improvements on highlevelnetwork api. Add easy encryption to highlevelnetwork api. May 25, 2018
@Faless Faless changed the title Add easy encryption to highlevelnetwork api. Add easy encryption to HighLevelMultiplayer Api. May 25, 2018
@mhilbrunner
Copy link
Member

mhilbrunner commented May 25, 2018

The first option, to add symmetric encryption APIs, should be done anyway and doesn't have much to do with networking. Something like proposed in PR #17721 but preferably with stronger defaults.

You could then encrypt data before sending (or before storing it to a file, or...).
Of course, this is only security by obscurity at best. A dedicated attacker would simply extract your key and decrypt the data.

Only way around that would be to add DTLS support (or a similar, encrypted transport that does the heavy lifting). Note that there is a GSoC project ongoing for adding WebRTC support; that uses DTLS by default, so should be encrypted.

Personally, I'm interested in the first option, to add APIs to encrypt/decrypt data manually, but not much in adding encryption support to the ENet backend. I think thats overkill. So what if somebody reads your position updates?

IMO, encrypting specific things like in-game chat is more than enough. The first option would suffice for that, or you could even use HTTPS for that right now, which would probably be enough for chats and similar messages. In the future, you may be able to use WebRTC to get encrypted transfer.

@jonbonazza
Copy link
Contributor

I think that symmetric key encryption is probably the correct approach here. Any sort of TLS approach is rather heavy handed and has enough overhead that I worry about resulting performance.

In regards to symmetric keys, I do request that a wide array of ciphers can be used. N9t only the number of bits, but also things like the chipher mode (e.g. GCM, CBC, etc..)

@raymoo
Copy link
Contributor

raymoo commented May 28, 2018

@jonbonazza Does your suggestion include some method of key agreement?

@Malkverbena
Copy link
Author

Does not Godot have a method for encrypting data already?

@jonbonazza
Copy link
Contributor

jonbonazza commented May 28, 2018

Actually, I was thinking about it more, and I don't think symmetric key encryption will work for this particular use case after all. On of the beauties of symenc is its simplicity. There is no key negotiation--both ends of the connection simply require the same key in order to enc and dec data. This is great when both the client and server are controlled by the same entity and live within the same datacenter, but for something like a game client this won't work at all and is virtually no better than having no encryption at all. Since the key is the same on both ends of the connection, there's nothing stopping a malicious party from grabbing the key from the client, intercepting the inflight data, decrypting it, modifying it, and renencrypting it before passing it on to server and the server would be none the wiser.

This is actually an ideal candidate for asymmetric encyrption. Honestly, Im not too experienced in assymmetric encryption options on top of UDP. TLS is certainly the most common form of assymetric encryption, but requires TCP. DTLS is a derivative of TLS but built for UDP. I have no experience with DTLS though, so I am unaware of its downsides, nor of any alternatives.

@jonbonazza
Copy link
Contributor

Also, like @Faless mentioned, even TLS doesn't completely solve the cheater issue, but then again, nothing will as once you distribute a client to another, uncontrolled machine, you can't trust anything that comes from it.
So yea.. Im not even sure encrypted traffic is worthwhile in a video game (at least not from the client to the server). You are paying the performance cost of any encryption scheme for virtually 0 gain other than "nay nay nay you can't see me", which if you are using an authoritative server (and you should be!) then even that doesn't matter anyway.

@tagcup
Copy link
Contributor

tagcup commented May 28, 2018

which if you are using an authoritative server (and you should be!) then even that doesn't matter anyway.

The clients can't know if it's indeed the authoritative server or they're being MITM'ed (to steal passwords etc) or it's a totally fake server (similar for client to client communications), and that's the one of the arguments for having TLS in place. And this is a problem that would need be addressed before worrying about cheating.

@jonbonazza
Copy link
Contributor

@tagcup the whole purpose for using an authoratative server is so it doesnt matter what the client thinks. The server is the validator and the arbiter. If the client sends something the server doesnt agree with, it ignores it.

@tagcup
Copy link
Contributor

tagcup commented May 28, 2018

It will matter when your players gets MITM'ed and get all their passwords and other personal information owned and you get sued by some.

@jonbonazza
Copy link
Contributor

So i think you are missing the point of this issue.

Passwords and personal info would never be sent via the high level networking library. For that, you would use an http client or something, which of course should have tls support.

This is for in game networking, which if you are at all a competant game developer, you would never send PII or credentials with.

@Malkverbena
Copy link
Author

Malkverbena commented May 29, 2018

@jonbonazza I totally agree with your point of view. In some moment the key will need to be negotiated and will can be caught. it is a waste of processing.

If you want to avoid cheaters, make the server authoritative (i.e. do not trust any data coming from clients), there is no other way (at least to my knowledge).

Sad, but true....

At this moment I would be content with 2 things:

  • A good HTTPS server/clients tutorial to exchage my super secret stuff.

  • Encryption to var. [Give a shield to this man... and let he fight ;-) ]

@Sslaxx
Copy link

Sslaxx commented May 29, 2018

If you're meaning gambling in particular (which, considering some of Godot's sponsors, would be logical) what are the legal requirements for that? I know they can be pretty arduous and probably beyond the scope of this issue (beyond possibly providing a framework).

@raymoo
Copy link
Contributor

raymoo commented May 29, 2018

@jonbonazza
Even with an authoritative server, a MITM could give bad inputs and make the player do things they wouldn't normally do (such as send all their money to the attacker's account). Maybe this could be solved by having symmetric encryption, but have the auth server provide an encryption key for the user session?

@Malkverbena

Encryption to var. [Give a shield to this man... and let he fight ;-) ]

Would have to be careful with this so that users don't get fake security because they implemented it badly. You would at least need to incorporate a (randomly-initialized) sequence number into the message. It would be ideal if the multiplayer API handled this on its own, because I think it would cover all cases of wanting to encrypt the high level multiplayer API.

@Faless
Copy link
Collaborator

Faless commented May 29, 2018

DTLS does protect you from MITM if used correctly.
AES encryption can protect you from MITM if you find a way to negotiate a secure key exchange.

There is no way we can implement secure key exchange out of the box, that's something game devs will have to take care of depending on their requirements and infrastructure (and we should give warning in the doc about it).

At the same time, DTLS can be used wrongly, as can SSL (and some devs do actually implement it wrong), but then again, game devs should know what they do.
If they care about security they should understand security. We can, as always, give warnings in the doc, but there isn't much more to do about that.

I think both should be implemented:

  • DTLS to (optionally) encrypt the whole ENet layer when needed adding 25 bytes of overhead per packet (websocket is missing SSL implementaiton server side, but clients already supports it).
  • AES encryption as a way to encrypt specific bytes and vars (when you only wants to encrypt some data). I think there is already some work to encrypt strings, but should be generalized to bytes if it is not already done (and please correct me if bytes can already be encrypted this way, as it will be one less thing to do).

@mhilbrunner
Copy link
Member

Agreed faless, thats the way to go. :)

@jonbonazza
Copy link
Contributor

Yes, DTLS (or any asymmetric ebcryption scheme) will protect from MITM, but when the client is on a user's machine nothing will protect the attacker from just grabbing your keys and sending w/e they want or performing outbound MITM that way. This is why most games dont use security at the transport layer already. You're free to use it in your game, of courae, but expect massive slowdowns (and depending on your game, it very well could render it unplayable) and minimal added security.

@mhilbrunner
Copy link
Member

mhilbrunner commented May 30, 2018

DTLS is fairly low-latency. The biggest overhead and increase in latency is in the initial handshake. During runtime, cost should be fine. WebRTC does use DTLS and seems to work for soft real time applications like VOIP, video streaming and games.

If you don't want that overhead, well, DTLS is of course going to be optional; you don't need to use encryption. We won't force you. :P

@Malkverbena
Copy link
Author

So, did you guys decided for the features on bellow?

  • Optional DTLS encrypt to the whole ENet layer.
  • AES encryption to bytes and vars.
  • SSL on WebSocket (Which already work on clients side)

@mhilbrunner
Copy link
Member

@Malkverbena I think thats a good summary. Someone has to actually implement those things though. Contributors welcome :)

@Malkverbena
Copy link
Author

I would love implement it all with my own hands, since these improvements benefits me directly.
But on my days off I don't have enough time to sleep 8 hours per day and when I'm on sea, I work 12 hours per day....
It's difficult even to read my messages with the terrible internet I got there.

@Malkverbena
Copy link
Author

Hello again folks. I'm back!
I'll stay on shore for while and will have some time to work on it. But I have no clue what the best way to start.
I'd like to work on AES encryption at first moment, since it's not that complicated.
So, maybe write a module to encrypt/decrypt?
What about a layout like:
my_module.encryption(data, key, options)

@mhilbrunner
Copy link
Member

mhilbrunner commented Jul 10, 2018

@Malkverbena There is an open PR implementing AES encryption methods like you propose, although I'd prefer a stronger mode/config/defaults than it currently implements. (#17721)

Best option for networking encryption for us still seems to be looking into DTLS.

@Malkverbena
Copy link
Author

@mhilbrunner What exactly you would like to see on that PR above?

@Malkverbena
Copy link
Author

Hey folks
I just started a encryption module. I still don't undestand how some process of Godot works than for now I prefer work with a module.
Initially I gonna work with AES 256 GCM since EBC does not provides an apropriate security level.
My doubts are:
Can Godot use OpenSLL or Crypto? I confess I didn't read the licenses.
If yes, any advice?

@Calinou
Copy link
Member

Calinou commented Jul 20, 2018

Can Godot use OpenSLL or Crypto? I confess I didn't read the licenses.
If yes, any advice?

Godot used OpenSSL until b33d10c; as of that commit (which will be in Godot 3.1), it now relies on mbedTLS.

@Malkverbena
Copy link
Author

I don't know this library.
This means days of study that I really don't want to spend.

@Malkverbena
Copy link
Author

Hey folks.
mbedTLS work with unsigned char and Godot provides String. Is there a good way to converto one to another?

@Faless
Copy link
Collaborator

Faless commented Jul 26, 2018

@Malkverbena unsigned char * is for bytes, not String (char *), you should use PoolByteArray .

@Malkverbena
Copy link
Author

Malkverbena commented Jul 26, 2018

Using PoolByteArray as input for cryptography can also be userful to network some way?
Not exacly related anymore.... String uses 1 or 2 bytes?

@Faless
Copy link
Collaborator

Faless commented Jul 26, 2018

Using PoolByteArray as input for cryptography can also be userful to network some way?

We would need to use uint8_t * directly instead for performance, but it's a start.

String uses 1 or 2 bytes?

String uses 1 or 2 bytes per character depending on the UTF8 encoding of the specific character.

@Malkverbena
Copy link
Author

Malkverbena commented Jul 26, 2018

We would need to use uint8_t *

Do you mean Vector<uint8_t> ?

Where can I find the documentation of Variant, String and Array? read documentation is faster than read the code...

@Faless
Copy link
Collaborator

Faless commented Jul 27, 2018

@Malkverbena
Copy link
Author

Hey!
I wrote this module as a laboratory. Just to get used with some godot's process.

https://github.com/Malkverbena/cripter

As I said before, my time is really short and often I have to sacrifice hours of sleep to code.
I would like someone take a look and tell if there is something whong or that could be done in a better way.
I wrote cbc function just for testing but my next plan is write gcm a function with authentiction.
For now it works only with bynary array, soon gonna with with Variant as well.

@Malkverbena
Copy link
Author

Malkverbena commented Aug 10, 2018

@mhilbrunner

I'd prefer a stronger mode/config/defaults than it currently implements.

I would appreciate some feedback.

For now it can encrypt/decrypt bytes and var using CBC and GCM. GCM naturally authentication requires authentication.
I'm also not sure if I'm writing on poolbytearray in the best way.
As I told, I wrote this module to learn before to think write something decent to Godot.

@Faless I'm not sure if I got what you meant. Anyway I'm using uint8_t. Not the best way yet but it's a experience for now.

@fire
Copy link
Member

fire commented Sep 17, 2018

The algorithm ed25519 is also part of tls 1.3 so it may be useful to expose.

@Faless Faless added this to the 3.2 milestone Dec 26, 2018
@raymoo
Copy link
Contributor

raymoo commented May 14, 2019

Not to discourage the development of the AES part, but I believe the DTLS portion of this issue is much more useful. If you have just the AES portion, there are many ways someone could try to use it with networking and produce insecure code.

The most obvious way is if they just used a fixed key, but even if you negotiate a new key per connection (through some external mechanism), and then communicate with the server by encrypting string arguments with that key, it can allow a MITM to forge bad inputs by replaying older messages sent by the client, since the same message will always have the same output if encrypted by the same key. Depending on the specific game, the attacker may also be able to guess the contents of the messages based on frequency, or by joining the same server and correlating in-game events with messages between the client/server.

I think you can make it secure by adding a sequence number to each message, but I'm not sure and I'm not a crypto expert. You would still have to do manual serialization of all the RPC arguments which would be a pain (but probably could be extracted into a convenient library if it had to be).

@Malkverbena
Copy link
Author

Malkverbena commented May 14, 2019

@raymoo I agree. For Internet communication, asymmetric cryptography is the best option. However I can think of at least half a dozen uses for symmetric cryptophraphy. It would be very useful at least to be able to encrypt an Raw Array using symmetric encryption.

@raymoo
Copy link
Contributor

raymoo commented May 21, 2019

What are some of those use cases? I only skimmed quickly through the thread, so sorry if some have already been listed.

@akien-mga
Copy link
Member

I think this is partially addressed by https://godotengine.org/article/basic-cryptography-ssl-improvements

Next step is DTLS, which is WIP and will be available in 4.0: https://godotengine.org/article/dtls-report-1

@akien-mga
Copy link
Member

Fixed by #36296.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.