mirror of
https://github.com/PrismarineJS/node-minecraft-protocol.git
synced 2024-12-20 04:22:22 -05:00
367c01567c
* Initial 1.19.1/2 signed chat impl * lint * remove node 15 nullish operators * fix undefined uuid error * handle player left * fix * add some feature flags * fix * Fix test to use new client.chat() wrapper method * refactoring * corrections, working client example * refactoring * message expiry checking * Fix UUID write serialization * Remove padding from client login to match vanilla client * Fix server verification * update packet field terminology * Add some tech docs Rename `map` field in Pending to not conflict with Array.map method * update tech doc * lint * Bump mcdata and pauth * add doc on playerChat event, .chat function * update doc * use supportFeature, update doc Co-authored-by: Romain Beaumont <romain.rom1@gmail.com>
54 lines
No EOL
4.1 KiB
Markdown
54 lines
No EOL
4.1 KiB
Markdown
## About chat signing
|
|
|
|
Starting in Minecraft 1.19, client messages sent to the server are signed and then broadcasted to other players.
|
|
Other clients receiving a signed message can verify that a message was written by a particular player as opposed
|
|
to being modified by the server. The way this is achieved is by the client asking Mojang's servers for signing keys,
|
|
and the server responding with a private key that can be used to sign messages, and a public key that can be used to
|
|
verify the messages.
|
|
|
|
When a client connects to the server, it sends its public key to the server, which then sends that to other players
|
|
that are on the server. The server also does some checks during the login procedure to authenticate the validity of
|
|
the public key, to ensure it came from Mojang. This is achieved by the client sending along a signature from Mojang's
|
|
servers in the login step which is the output of concatenating and signing the public key, player UUID and timestamp
|
|
with a special Mojang private key specifically for signature validation. The public key used to verify this
|
|
signature is public and is stored statically inside node-minecraft-protocol (src/server/constants.js).
|
|
|
|
Back to the client, when other players join the server they also get a copy of the players' public key for chat verification.
|
|
The clients can then verify that a message came from a client as well as do secondary checks like verifying timestamps.
|
|
This feature is designed to allow players to report chat messages from other players to Mojang. When the client reports a
|
|
message the contents, the sender UUID, timestamp, and signature are all sent so the Mojang server can verify the message
|
|
and send it for moderator review.
|
|
|
|
Note: Since the server sends the public key, it's possible that the server can spoof the key and return a fake one, so
|
|
only Mojang can truly know if a message came from a client (as it stores its own copy of the clients' chat key pair).
|
|
|
|
## 1.19.1
|
|
|
|
Starting with 1.19.1, instead of signing the message itself, a SHA256 hash of the message and last seen messages are
|
|
signed instead. In addition, the payload of the hash is prepended with the signature of the previous message sent by the same client,
|
|
creating a signed chain of chat messages. See publicly available documentation for more detailed information on this.
|
|
|
|
Since chat verification happens on the client-side (as well as server side), all clients need to be kept up to date
|
|
on messages from other users. Since not all messages are public (for example, a player may send a signed private message),
|
|
the server can send a `chat_header` packet containing the aforementioned SHA256 hash of the message which the client
|
|
can generate a signature from, and store as the last signature for that player (maintaining chain integrity).
|
|
|
|
In the client, inbound player chat history is now stored in chat logs (in a 1000 length array). This allows players
|
|
to search through last seen messages when reporting messages.
|
|
|
|
When reporting chat messages, the chained chat functionality and chat history also securely lets Mojang get
|
|
authentic message context before and after a reported message.
|
|
|
|
## Extra details
|
|
|
|
### 1.19.1
|
|
|
|
When a server sends a player a message from another player, the server saves the outbound message and expects
|
|
that the client will acknowledge that message, either in a outbound `chat_message` packet's lastSeen field,
|
|
or in a `message_acknowledgement` packet. (If the client doesn't seen any chat_message's to the server and
|
|
lots of messages pending ACK queue up, a serverbound `message_acknowledgement` packet will be sent to flush the queue.)
|
|
|
|
In the server, upon reviewal of the ACK, those messages removed from the servers' pending array. If too many
|
|
pending messages pile up, the client will get kicked.
|
|
|
|
In nmp server, you must call `client.logSentMessageFromPeer(packet)` when the server receives a message from a player and that message gets broadcast to other players in player_chat packets. This function stores these packets so the server can then verify a player's lastSeenMessages field in inbound chat packets to ensure chain integrity (as described above). |