godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
90.71k stars 21.12k forks source link

Add easy encryption to HighLevelMultiplayer Api. #19110

Closed Malkverbena closed 4 years ago

Malkverbena commented 6 years ago

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 commented 6 years ago

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

raymoo commented 6 years ago

Why specifically leaderboards?

Zylann commented 6 years ago

@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 commented 6 years ago

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

Zylann commented 6 years ago

@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 commented 6 years ago

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

Malkverbena commented 6 years ago

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 commented 6 years ago

CC @Faless @mhilbrunner

Faless commented 6 years ago

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

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.

mhilbrunner commented 6 years ago

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 https://github.com/godotengine/godot/pull/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 commented 6 years ago

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 commented 6 years ago

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

Malkverbena commented 6 years ago

Does not Godot have a method for encrypting data already?

jonbonazza commented 6 years ago

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 commented 6 years ago

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 commented 6 years ago

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 commented 6 years ago

@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 commented 6 years ago

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 commented 6 years ago

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 commented 6 years ago

@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:

Sslaxx commented 6 years ago

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 commented 6 years ago

@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 commented 6 years ago

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:

mhilbrunner commented 6 years ago

Agreed faless, thats the way to go. :)

jonbonazza commented 6 years ago

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.

jonbonazza commented 6 years ago

FWIW, in most game genres, getting latency down to an acceptable level for a majority of regions is already difficult enough. Adding any kind of encryption is going to make things imposdible in many cases.

Faless commented 6 years ago

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

Because that's not the problem that encryption is trying to solve. It is not something to avoid cheaters, for that, you need an authoritative server. Encryption do not relieve you from doing validation of data received from clients.

If you are referring to user catching some malware and getting their account hijacked, again, that's not something encryption can fix.

Encryption is for ensuring that data from one end (user), to the other (server, or other user), cannot be read by anyone else (confidentiality), ensuring that the data is not altered during the trip (integrity). And DLTS perfectly achieve this. A very simple example is having a user insert a password to access a server and not wanting everyone in the way to read the password.

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). in most game genres, getting latency down to an acceptable level for a majority of regions is already difficult enough. Adding any kind of encryption is going to make things imposdible in many cases.

Why do you think so? Why would encryption considerably increase latency? Do you have any data supporting this statement? As an example, AES is a quite fast algorithm, and will take very few cycles of your processor compared to things like computing physics.

mhilbrunner commented 6 years ago

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 commented 6 years ago

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

mhilbrunner commented 6 years ago

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

Malkverbena commented 6 years ago

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 commented 6 years ago

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 commented 6 years ago

@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. (https://github.com/godotengine/godot/pull/17721)

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

Malkverbena commented 6 years ago

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

Malkverbena commented 6 years ago

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 commented 6 years ago

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

Godot used OpenSSL until https://github.com/godotengine/godot/commit/b33d10ccdfff52611ff508bbec64d65e0d88da70; as of that commit (which will be in Godot 3.1), it now relies on mbedTLS.

Malkverbena commented 6 years ago

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

Malkverbena commented 6 years ago

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

Faless commented 6 years ago

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

Malkverbena commented 6 years ago

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 commented 6 years ago

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 commented 6 years ago

We would need to use uint8_t *

Do you mean Vector ?

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

Faless commented 6 years ago

@Malkverbena http://docs.godotengine.org/en/latest/development/cpp/index.html

Malkverbena commented 6 years ago

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 commented 6 years ago

@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 commented 6 years ago

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

raymoo commented 5 years ago

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 commented 5 years ago

@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 commented 5 years ago

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

akien-mga commented 4 years ago

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