Yes, this is a way to establish authenticity through the use of a so-called "shared secret".
In practice you could do it using the HMAC algorithm and a shared key between the server and clients.
Notice that here, there is a problem with shared keys: that is that the whole system is not secure as soon as one client is breached.
There are also other ways to establish authenticity of messages without this problem by the mean of public key cryptography.
In this case your server would be the only one knowing the secret key, and would sign its messages with it, so that the clients, knowing the public key of the server could verify the authenticity of the messages.
Typical algorithms to do so are ECDSA or Ed25519.
Edit
As requested, here are more details regarding how these would work in practice:
HMAC
This is almost exactly as you described in your own edit.
- You create a secret HMAC key, which you store on both the server and the clients.
- You have a message which you want to authenticate, so you just "HMAC" it on the server using the secret HMAC key, and you send both the message and the HMAC digest to your client(s).
- The client receives the message and the HMAC digest and computes the HMAC digest of the message, and then verifies it matches the one it received.
There is just one slight caveat I have with your way:
you pass the value str(payload["key"]).encode("utf-8")
as the msg
in your HMAC call, but what is contained in your payload["key"]
value?
You would rather have your payload itself being passed to the HMAC and then append the hexdigest to the message, thus you'd have a structure a bit like this for your messages:
{
"payload": {
"boolean": true,
},
"mac": {
"hmac-digest": "6eb6a866856dc7ea74c0d6bd41993106f696cc5091f88f188efbb23def6d248b"
}
}
Now, as you said in your edit, HMAC values being deterministic, if you authenticate twice the same message, you'd get twice the same digest.
But HMAC is about protecting authenticity of the messages, not confidentiality. (Notice that with HMAC, you get both authenticity and integrity of the message.)
Also, it is true that HMACed messages are trivially vulnerable to replay attacks, but so are public-key signed message.
Adding a replay protection to your protocol is not that easy, and usually requires being stateful.
To have replay attack protection, you'd typically need to have a message index value, and keep track (thus being stateful) of the said index on each clients. (And reject any message that does not increase the index value.)
{
"payload": {
"boolean": true,
"index": 12
},
"mac": {
"hmac-digest": "a1b0271d1eea012c81f06488645ce026914e095d9d770d7d213efbd968be3fe2"
}
}
But notice that this is still vulnerable to replay attacks between clients, if all clients are not getting the same message at the same time...
Thus, you might want to include sender and receiver data in your payload, so that these are authenticated as well... as you can see the complexity of your protocol is increasing relatively fast!
Public key crypto
So, if you are to use public key crypto to authenticate your messages, the process would only differ slightly from the previous workflow:
- You create a private key and its corresponding public key on the server and store them there.
- You store the public key of the server on each of your clients.
- You have a message which you want to authenticate, so you sign it on the server side using the private key, and you send both the message and the signature to your client(s).
- The client receives the message and the signature and uses the public key of the server to verify that the signature was indeed produced by someone knowing the server's private key.
There a multiple algorithm to do so:
- ECDSA
- Ed25519
- RSA-PSS
Notice that the same caveats as with HMAC applies here: you might need to authenticate more than just the message to avoid replay attacks and any other abuse of your protocol.