Preventing Replay Attacks with Timestamps and Nonces in PHP
The article explains replay attacks, describes how using a timestamp, a nonce, or a combination of both can protect API requests, and provides complete PHP code examples for signing and verifying requests to ensure each call is accepted only once.
Replay attacks (also called replay or playback attacks) repeatedly resend a previously captured valid API request, allowing an attacker to fraudulently invoke the same operation.
One simple mitigation is to include a timestamp in each HTTP request, sign the timestamp together with other parameters, and reject the request on the server if the timestamp differs from the current time by more than 60 seconds.
Example of generating a timestamp‑based signature in PHP:
Verification of the timestamp on the server side:
60) {
die("请求超时");
}
?>Because an attacker may capture a request within the 60‑second window, a nonce (Number used once) can be added. A nonce is a random value that must be unique for each request and is stored on the server (e.g., in a Redis set) to detect duplicates.
PHP code to create a nonce‑based signature:
Verification of the nonce:
sget("nonceList");
if (in_array($nonce, $nonceList)) {
die("请求仅一次有效");
}
?>Storing each nonce in a short‑lived collection prevents replay within the collection’s lifetime, but the collection can grow; therefore it should be cleared regularly (e.g., every 60 seconds).
For stronger protection, both timestamp and nonce can be used together. The timestamp limits the replay window, while the nonce ensures uniqueness within that window, allowing the server to keep only a small set of recent nonces.
Combined signing example:
Combined verification logic:
sget("nonceList");
// set collection expiration to 60 seconds
if (empty($nonceList)) {
$redis->explre("nonceList", 60);
}
if ($nowTime - $timestamp > 60) {
die("请求超时");
}
if (in_array($nonce, $nonceList)) {
die("请求仅一次有效");
}
if ($sign != md5($userInfo . $token . $nonce . $timestamp)) {
die("数字签名验证失败");
}
$redis->sadd("nonceList", $nonce);
?>With this approach, any replay attempt within 60 seconds is blocked by the nonce check, and attempts after 60 seconds are blocked by the expired timestamp, providing robust defense against replay attacks.
Laravel Tech Community
Specializing in Laravel development, we continuously publish fresh content and grow alongside the elegant, stable Laravel framework.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.