You can use a simple HMAC to check that id
remains unchanged, this will be safe until no one knows the key you use, of course it must be strong and securely generated, I will explain this as well.
In addition you should make sure that you can not get HMACs from other accounts, otherwise it would be the same as having the key.
/! \ Do not use the keys mentioned in the examples.
In general, something like:
$id = '1234';
// Este é o id do usuário, que deve estar associado de alguma forma segura.
$chave = pack('H*', '07e8796b87caa27d793dbe2ecfa7c85f753a9c920cb5d1394fbc36c20f1755b818c9afe37fb453ebf42724c8670d365ca9f0d12d49e31ea843023126f3174df9');
// Esta sua chave secreta e segura que foi gerada por você.
$hmac = hash_hmac('sha512', $id, $chave);
// Este é o resultado do HMAC de SHA-512.
<form action="avaliacao.php" method="post">
<input name="id" type="hidden" value="<?= $id ?>" />
<input name="hmac" type="hidden" value="<?= $hmac ?>" />
<input type="submit" name="avaliacao" value="1" />
<!-- ... Resto das outras opções -->
</form>
Then check to see if there has been a change:
$chave = pack('H*', '07e8796b87caa27d793dbe2ecfa7c85f753a9c920cb5d1394fbc36c20f1755b818c9afe37fb453ebf42724c8670d365ca9f0d12d49e31ea843023126f3174df9');
if(!isset($_POST['hmac'], $_POST['id'])) {
echo 'Erro: faltam dados';
exit;
}
$isHMACValido = hash_equals(
hash_hmac('sha512', $_POST['id'], $chave),
$_POST['hmac']
);
// Comparamos de maneira segura e em tempo contante o HMAC enviado pelo usuário e o computado agora.
if(!$isHMACValido){
echo 'Erro: Dados foram manipulados';
exit;
}
// Chegou até aqui está tudo certo!
// ...
What protection does this bring?
- Changing
id
by a user who does not know the key.
How is this protection achieved?
- HMAC is an option of type
H(K⊕opad||H((K⊕ipad)||m)
, so two different messages ( m
, in this case id
) different result in a different HMAC. A malicious user will be able to modify both (eg send: id=99&hmac=aaaa
), but this will be compared to the new HMAC (we will do the hmac, id, key), obviously it will be different from the hash sent by the user.
Is there no risk?
From the HMAC ...
CPA attacks do not work, even if the attacker creates thousands of accounts (thus having several valid HMACs for each account) he will have no clue what the key is used for.
-
Exhaustive search attacks will always work, however they are 512 bits, this results in more than 2 ^ 512 possibilities, which makes the attack unfeasible, at least until this moment.
-
Exhaustive search attacks against the key also work. For this the key must be secure and generated from a secure CSPRNG and strong enough, otherwise brute force attacks will be fast, also use 512 key bits.
-
MiTM attacks are valid. If you do not use HTTPS one person monitoring the network can get the other user's HMAC, this would not only affect the HMAC, but the whole system.
From the application ...
-
It should not be possible for the user to have access to other HMACs. The id
must be unique to it. Your application should not say what the HMAC of an X, being X sent by the user, allow this to override any security.
The key must be kept secret and should not be known by the client, if the key is exposed it will be possible to compute valid HMACs.
To generate a secure key use:
echo unpack('H*', random_bytes(32))[1];