minetest
minetest copied to clipboard
Add network encryption into minetest
Problem and Solutions
Currently, Minetest packets are unencrypted, which leads to several privacy problems. We should encrypt them, to avoid man-in-the-middle attack and eavesdrops.
Alternatives
Make a CSM, which works with the Server, to encrypt serious data like commands or chatroom messages.
Passwords are encoded using SRP before they're sent over the network, requiring quite some efforts by the attacker. See also: #1943 -> PR #2620.
DTLS would be a possibility instead of pain UDP. However, the transferred packets are usually very small (< 1 KiB), with unreliable parts mixed into it (player movements). I don't see any need to encrypt the network - this is a game, not a nuclear reactor remote software (which shouldn't exist in the first place ;) ).
Possible close, really? Chat and form traffic should be encrypted. Maybe meta as well. Anything that involves big blobs of text.
As it is, a MITM attack can be used to impersonate someone with privileges and send commands in their stead, including very dangerous ones like #10163, making this a vector for a server to get compromised. (We have enough botnets on the internet as it is.)
In addition, lots of kids play this game without knowing that their communications can be trivially overheard. By not encrypting the traffic, you are making it very easy for some creep to datamine them. (Researching the victim is usually the first step for kidnappers, traffickers, etc. If you think they wouldn't bother bugging someone's home connection, think again.)
Or maybe somebody lives in a country with a less than stellar human rights situation, and slips up in conversation. One word might be enough to land you in trouble, or put you on some list. Do you think an authoritarian government cares if it happened in a block game?
Finally, if a zero day is found in some more complicated portion of the client environment such as forms, malware can be spread without having to compromise the server itself. Any node along the way can do it. Yikes.
And if any of those things happen, the server owner might have to deal with some unpleasant fallout too, depending on the circumstances.
The question about encrypting communication and securing a public server in 2020 should never be "if" but "how". Don't wait until any of the above things happen, do it now.
~~I consider this low priority at this time.~~ Passwords are protected using SRP, chat is not privileged, and connection hijacking is not trivial (you need to be on a node between the server and the client). Minetest is also not that big of a target.
This will probably be needed when server-sent client-side scripting is added, to ensure that any code is sent from the server and not a MiTM.
Now-a-days, encryption has good hardware support so performance shouldn't be a problem. We can also use the handshake to let the client and server agree on whether encryption should be used, allowing network compatibility to be kept. This would introduce a downgrade attack, but we could use the serverlist to make the client require encryption when connecting. Server-sent client-side mods could also require encryption.
Authentication of the server could be an issue, the best way to do that would be ~~two methods~~:
- the server list could contain the public key of the server
- ~~the public key of a server could be verified by its domain name, using standard internet CAs~~
I guess it depends on how secure you want it to be
Minetest is not big but in my opinion we shouldn't wait with security until someone dies. It's not like encryption is hard either. Using the master server as a key authority should be good enough as a default. Third party CAs would require some extra steps to set up, like having a domain in the first place. That part need not be in the initial implementation. Plaintext connections would still be supported, but with a little string on the loading screen warning you about it, and maybe a padlock icon in the list for secure servers.
And oh yeah, I forgot SSCSM. That requires encryption, not for secrecy but for integrity. You might want to add this issue to the SSCSM project.
The idea behind domain certs and CAs would be to allow authentication for servers not on the server list, but that's a much lower priority and that solution doesn't work for all servers as you said
CAs would help but they're a bit more work, hence the lower priority for them. In the meantime, being able to manually inspect the cert would be useful for the unlisted server case.
Isn't SRP able to create a symmetric session key for encryption?
Problems: First SRP is still insecure
Passwords are encoded using SRP before they're sent over the network, requiring quite some efforts by the attacker. See also: #1943 -> PR #2620.
DTLS would be a possibility instead of pain UDP. However, the transferred packets are usually very small (< 1 KiB), with unreliable parts mixed into it (player movements). I don't see any need to encrypt the network - this is a game, not a nuclear reactor remote software (which shouldn't exist in the first place ;) ).
I think player move should encrypt because a hacker can move you into lava if player move are not encrypted
I asked on stack overflow: https://stackoverflow.com/questions/63171893/are-there-any-network-encryption-for-udp-that-support-big-packet
I think player move should encrypt because a hacker can move you into lava if player move are not encrypted
That would require the hacker to do a middle man attack which is nothing you just do for killing a player in a game...
Sure there are Udp encryption algorithms. The Problem is just that encryption/decryption takes time, so a fast one should be used.
The reason movement shouldn't be encrypted is because it's a low latency, high frequency kind of information which must be sent as quickly as possible, and there's nothing sensitive about it. Same goes for plain button inputs.
I do wonder about the possibility of griefing a server with spoofed input packets, re-enacting the Dancing Plague of 1518. But can an attacker convincingly spoof input and movement packets without any information about the peers? Or maybe there's a way to trick the server into revealing the peer information?
The reason movement shouldn't be encrypted is because it's a low latency, high frequency kind of information which must be sent as quickly as possible, and there's nothing sensitive about it. Same goes for plain button inputs.
I disagree, you should either encrypt everything or nothing(except auth) It's overcomplicated to not do it. You shouldn't notice the time needed for encryption when using a nice algorithm.
I do wonder about the possibility of griefing a server with spoofed input packets, re-enacting the Dancing Plague of 1518. But can an attacker convincingly spoof input and movement packets without any information about the peers? Or maybe there's a way to trick the server into revealing the peer information?
Sure! You just need to be somewhere between the server and client. Than you could pretty much spoof anything. You just don't get so easy between them ;)
I personally don't care if the connection is encrypted or not. Nobody would do such a hack to a minetest gaming server...
Well I disagree with this disagreement, anything you do on the server, you have to multiply by the amount of players connected. The cost adds up quickly. If there is a trivial way to pass movement data as plaintext, do it.
Hmm, that's true. Maybe the best is not to add more encryption and keep everything as it is. Auth is encrypted that's the main thing.
Another idea is to encrypt only one channel(and put everything trusty in it)
The encryption could just be done at a low level, everything in the UDP packets past the protocol id and source peer id could be encrypted (except auth because it already uses SRP and would be used for key agreement).
Badly implemented crypto might just provide a false sense of security, minetest being relatively small means not many eyes checking if the implementation is correct (for instance the SRP implementation had a bug in it that resulted in the salt not being random in some circumstances for ~4 years before anyone noticed). If you are concerned the risks of game chat, etc being intercepted you are likely better of informing people of relatively secure means of communication online (PGP, Signal Protocol, OTR, etc) and how to use them correctly. Public key cryptography might be useful for other purposes (maybe uniquely identifying servers for SPCSM even if the domain or port changes?) but I think it would be ill-advised to promote it as a protection against eavesdropping.
I suggest limiting the scope of this issue to what @hecktest proposed:
Chat and form traffic should be encrypted. Maybe meta as well. Anything that involves big blobs of text. As it is, a MITM attack can be used to impersonate someone with privileges and send commands in their stead, including very dangerous ones like https://github.com/minetest/minetest/issues/10163, making this a vector for a server to get compromised. (We have enough botnets on the internet as it is.)
Chat is particularly important here.
I suggest limiting the scope of this issue to what @hecktest proposed:
Chat and form traffic should be encrypted. Maybe meta as well. Anything that involves big blobs of text. As it is, a MITM attack can be used to impersonate someone with privileges and send commands in their stead, including very dangerous ones like #10163, making this a vector for a server to get compromised. (We have enough botnets on the internet as it is.)
Chat is particularly important here.
Why not just authenticate and encrypt all packets with ChaCha20 (or perhaps Salsa20) and Poly1305? This way the only things a malicious network can do is drop/delay packets and see packet sizes and timing. I really doubt that this would create a noticeable overhead if vectorized assembly implementations are used.
I'd recommend against AES because without hardware acceleration (e.g. on mobile devices) it's slow and often vulnerable to cache-timing attacks and preventing them makes it slower.
I am in favor of full network encryption using DTLS or similar, but I want to add that encrypting chat end-to-end can be done with CSMs. As far as I know, the client Waspsalive contains an implementation of that.
For network cryptography, you could do this as followed:
- When initiating handshake it is best to use TLS or having a third party server to serves as a validator (either certificate authority or Serverlist server could do this) of this handshake session to avoid Trust on First Contact issue.
- I generally suggest using Diffie-Hellman Elliptic Curve Cryptography on Curve25519 for public key exchange between the game server and the client. If we're on UDP instead of TCP, I would advise against ChaCha20 since it's a streaming protocol whereas UDP is stateless and can be arranged out of order which would pose a problem for streaming cipher. Instead, I would normally suggest either using AES, Threefish, or other symmetric block cipher algorithm (Just don't use 3DES please.)
- You should only encrypt information that are sensitive like chat and authentication information, it doesn't make much sense to encrypt something like player movement however. You can instead use HMAC which is Hashed Message Authentication Code to ensure that packet is not tampered with and that it have a very low cost on computation requirement for such validation. HMAC can be summarized to simply hashing the content of the packet, encrypting the said hash and then append at the end of the packet.
Hope this helps.
I really doubt it makes any sense discussing about specific ciphers at this point...
What we need is:
(1) A way to authenticate servers.
The difficulties here are:
- Creating a LAN server should not be much more complicated than before.
- It should still be possible to host a (global) minetest server without a domain and/or webserver, because that would be a barrier that prevents some servers from actually using the secure networking.
- More?
To do this, we can generate X.509 certificates for the server. We could add multiple possible ways (all possible, but optional) to trust it, e.g.:
- Via trust on first use (TOFU): The certificate's fingerprint can be stored in the server favourites. (Only works for ensuring it's still the same server, and can become outdated. We might want to identify servers by a UUID.)
- Semi-automatically via an out-of-band channel: A fingerprint of the certificate, that the user copies from somewhere (i.e. a forum post).
- Via the web PKI: Host a webserver on the same domain.
- Manually via an out-of-band channel: By displaying a fingerprint on first server join. On a LAN server, the user can then maybe just ask the hoster if the checksum is correct.
- Via some semi-central (that is, central, but the center can be configured, like the public server list) system.
(One could just use the shared key from SRP as pre-shared-key, but that would imo not be sufficient, as players can choose very weak passwords. It would however be good to use the SPR key to verify the certificate fingerprint again.)
(2) A network protocol for secure channels.
The simplest here would be to just swap UDP with DTLS.
We could also optionally compile minetest with a QUIC implementation, with the datagram extension for unreliable packets. In addition to security, this would also give us other networking benefits, like different priorities for different packets.
(FYI, gnutls looks to me like a good choice for DTLS (supports DTLS 1.2, is widely used, is easy to use, and we already depend on it through libcurl-gnutls), ngtcp2 could be used for QUIC (MIT licensed, can use gnutls connection as TLS backend).)
(3) An addition to the minetest protocol to negotiate what protocol should be used, and to download the certificate.
This should happen before the normal minetest handshake happens.
Client and server both have a priority list for supported protocols (set via settings), i.e. "encrypted_QUIC,partly_encrypted_DTLS,encrypted_DTLS,unencrypted_UDP".
The client can then before join download the supported protocols from the server, and chooses its favourite one. (This should ideally be optional for the server, to hide that there's a minetest server running.)
It also has to download and check the certificate.
We could additionally store the certificate and the supported protocols in the public server list.
Running a minetest server on a http3 port would also be a nice feature.
If we're on UDP instead of TCP, I would advise against ChaCha20 since it's a streaming protocol whereas UDP is stateless and can be arranged out of order which would pose a problem for streaming cipher. Instead, I would normally suggest either using AES, Threefish, or other symmetric block cipher algorithm (Just don't use 3DES please.)
ChaCha20 is not a streaming protocol, it's a stream cipher which is no worse than a block cipher for encrypting packets. You can get multiple streams out of one key using different nonces (you need nonces either way unless you're using something like ECB mode).
You should only encrypt information that are sensitive like chat and authentication information, it doesn't make much sense to encrypt something like player movement however.
It's simpler to just authenticate and encrypt everything rather than trying to decide what is and isn't sensitive. I doubt it would make a noticeable different to performance.
You can instead use HMAC which is Hashed Message Authentication Code to ensure that packet is not tampered with and that it have a very low cost on computation requirement for such validation.
I'd prefer a MAC like Poly1305, which is faster and if packets are limited to 512 bytes it can be mathematically proven (assuming random keys are used) that an attacker making n forgery attempts has a success probability of at most n/2^98. This means, for example, to get even a one in a billion chance of successful forgery an attacker must send more than more than 4 zettabytes of authentication tags.
HMAC can be summarized to simply hashing the content of the packet, encrypting the said hash and then append at the end of the packet.
That's not what HMAC does.
I was referencing the HMAC code from memory when working with BouncyCastle which literally does this at the time. Also I have lost interest in using nor do I care to contribute to Minetest, so congratulation everyone.
I think we have to encrypt at least two things:
- Chat messages, contains
/setpasswordand/or messages the government dislike. - SSCSM, which require encryption to ensure safety.
There can also be confidential text in formspecs, formspec fields (filled out by client), mapblocks and whatnot. It makes not much sense thinking about what we don't need to encrypt before benchmarking if there's any real performance penalty by just encrypting everything.
And SSCSM doesn't need encryption if we don't trust the server more than we already do.
For what it's worth - using TLS also comes with the benefit of allowing virtual hosts using SNI. Allowing multiple services to listen on the same port at the same IP can be very useful for hosting solutions.
I suggest limiting the scope of this issue to what @hecktest proposed:
Chat and form traffic should be encrypted. Maybe meta as well. Anything that involves big blobs of text. As it is, a MITM attack can be used to impersonate someone with privileges and send commands in their stead, including very dangerous ones like #10163, making this a vector for a server to get compromised. (We have enough botnets on the internet as it is.)
Chat is particularly important here.
Why not just authenticate and encrypt all packets with ChaCha20 (or perhaps Salsa20) and Poly1305? This way the only things a malicious network can do is drop/delay packets and see packet sizes and timing. I really doubt that this would create a noticeable overhead if vectorized assembly implementations are used.
I'd recommend against AES because without hardware acceleration (e.g. on mobile devices) it's slow and often vulnerable to cache-timing attacks (preventing them makes it slower).
QUIC may be a good choice for Minetest:
- QUIC has useful features in addition to security: customizable congestion control, reliable and unreliable data transmission, prioritising of streams and perhaps even control of the latencies. These features are needed in Minetest, e.g. mapblock packets should be prioritised lower than packets which hurt or teleport a player. This is also an advantage over TLS.
- Efficient implementations of QUIC probably are or will be available. HTTP/3, which uses QUIC, has been standardized in 6 June 2022 and is used in the web, which could be a reason for a high demand for efficient QUIC.
- Minetest developers do not need to implement and maintain their own low-level protocol.
- Implementing a custom secure protocol would be bad for security in general because there is no proof that the custom protocol is really secure and most Minetest developers are not security experts I think.
It should be possible to get a shared key from SRP (the player's already secure login) and pass it to QUIC to establish the secure channel.
I'd recommend against AES because without hardware acceleration (e.g. on mobile devices) it's slow and often vulnerable to cache-timing attacks (preventing them makes it slower).
~I think Mobile devices which don't support browsing with a modern web browser are often too slow to play Minetest at all. I assume that modern web browsers always use AES for HTTPS (HTTP with TLS), so these devices should support AES well.~ Edit: Mobile devices often don't support AES implemented in hardware (see comment below).
Implementing a custom secure protocol would be bad for security in general because there is no proof that the custom protocol is really secure and most Minetest developers are not security experts I think.
If we used ChaCha20 with Poly1305 to encrypt and authenticate raw UDP packets it wouldn't be too hard to prove security using indifferentiability:
In the ideal world, the client C and the server S are both is sending packets with distinct 64-bit nonces (these could replace Minetest RUDP's sequence numbers). After a packet is sent, the adversary A sees its size and nonce, and gains the capability to pass it on (possible repeatedly) to its intended recipient. The RUDP layer would stil need to be made robust against malicious packet dropping, delaying and replaying for security in this ideal world.
In the real world, the client C and the server S are both exchanging packets with the adversary B as specified by the protocol.
To prove security, construct a simulator Σ which simulates the capabilities of a real-world adversary using the capabilities of an ideal world adversary. This means the capabilities (Σ(A), C, S) and (B, C, S) are indistinguishable, which could be proven under the assumption that ChaCha20 is secure.
I assume that modern web browsers always use AES for HTTPS (HTTP with TLS), so these devices should support AES well.
Your assumption is incorrect, see https://blog.cloudflare.com/do-the-chacha-better-mobile-performance-with-cryptography/.
This issue seems like stale for a while.
What about using WebRTC ?
- It uses TLS for handshake, and DTLS for UDP
- Can carry data packages (eg. game data)
- All of the cryptography decisions are offloaded to a standards workgroup
- Brings in easy to support browser networking as well
- Already established and battle tested libraries exist almost for all platforms