开发者

How to create digital signature that can not be used to reproduce the message twice

开发者 https://www.devze.com 2023-02-11 17:23 出处:网络
I am creating a client-server application and I\'d like to send data from server to client securely. Using public/private key algorithms makes sense and in PHP we can use openssl_sign and openssl_ver

I am creating a client-server application and I'd like to send data from server to client securely.

Using public/private key algorithms makes sense and in PHP we can use openssl_sign and openssl_verify functions to check that the data came by someone who has the private key.

Now imagine that one of the actions sent by server to client is destructive in nature. If somebody uses an HTTP sniffer to catch this command (which will be signed properly) how can I make sure that the command was executed only when our server sent it and not by a hacker simply reproducing the same command?

OK while writing this I fig开发者_开发问答ured out that using auto-increment id to number every sent message could be a simple solution to the problem. Client would just have to check that the incoming message ID is never smaller that the current ID they have stored.


Include a nonce (random value, unique for each message) to the message, and on the client keep track of used nonces. I.e. if the attacker takes the signed message and resends it later, the nonce is already used by the client, so the client won't handle the message for the second time.


If somebody uses an HTTP sniffer to catch this command (which will be signed properly) how can I further protect the communication to ensure that only commands coming from our server get processed by the client?

In short, you can't. If someone can sniff the network traffic, they would be able to get anything that you send. So unless you pre-share a secret key via an out-of-band mechanism (such as a phone call), you can't reliably do this. If you pre-share the secret, then all you need to do this:

Server:

$message = 'foomessage';
$message .= ':' . hash_hmac('md5', $message, $sharedSecret);

Client:

list ($message, $hmac) = explode(':', $message, 2);
if ($hmac != hash_hmac('md5', $message, $sharedSecret)) {
    die('invalid signature');
}

Note that this is 100% dependent on the shared key. If someone else got a hold of it, all your signed communication would be tampered with.

Another possible way of detecting a sniffer style attack is to use a syn-ack approach. Basically, you store a number on the server and on the client. Each request, you increment both numbers. You then include that number in a hmac calculation. Since the client and the server talk to each other, both counts should always be in sync. But if they are ever off, you know that either some communication failure has taken place, or someone has injected a command (hijacked) with the wrong count. So while it wouldn't "prevent" a replay attack directly, it would make it MUCH harder since the attacker would need to keep track of every single HTTP request between the server and the client.

But the bottom line is that anyone who's compromised the network to pull off a MITM attack will be able to get around almost anything you can throw at them... The best ways to secure against it are to pre-share secret keys in an out-of-band manor (such that a HTTP scanner wouldn't be able to detect the shared key). Then just hmac any message with that pre-shared key.


Sounds like you need an interpretation of the "One-Time Pad Cipher" in PHP?

One Time Pad The one-time pad is a long sequence of random letters. These letters are combined with the plaintext message to produce the ciphertext. To decipher the message, a person must have a copy of the one-time pad to reverse the process. A one-time pad should be used only once (hence the name) and then destroyed. This is the first and only encryption algorithm that has been proven to be unbreakable.

To encipher a message, you take the first letter in the plaintext message and add it to the first random letter from the one-time pad. For example, suppose you are enciphering the letter S (the 19th letter of the alphabet) and the one-time pad gives you C (3rd letter of the alphabet). You add the two letters and subtract 1. When you add S and C and subtract 1, you get 21 which is U. Each letter is enciphered in this method, with the alphabet wrapping around to the begining if the addition results in a number beyond 26 (Z).

To decipher a message, you take the first letter of the ciphertext and subtract the first random letter from the one-time pad. If the number is negative you wrap around to the end of the alphabet.


Make an hash (md5) out of each message and add the microtime timestamp to it.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号