PHP 7.1 时间戳安全校验需同时满足时间窗口(±300秒)和签名防篡改:将uid、action、timestamp按序拼接后用hash_hmac生成签名,服务端用hash_equals比对,并强制int转换timestamp防注入。

PHP 7.1 中实现时间戳安全校验,核心是防止重放攻击(replay attack):即攻击者截获合法请求后,在有效期内重复发送。关键在于验证时间戳是否“新鲜”,而非单纯检查格式或范围。
校验逻辑:时间窗口 + 签名防篡改
仅校验时间戳是否在当前 ± 若干秒内是不够的——必须确保该时间戳与请求其他参数(如用户 ID、操作类型、随机 nonce)一起被签名,且签名不可伪造。否则攻击者可自行构造合法时间戳并重放旧请求。
- 服务端生成时间戳(如
time()),精度为秒即可(PHP 7.1 不原生支持毫秒级 `time(true)`,可用microtime(true)取整) - 将时间戳与其他关键参数拼接(推荐按固定顺序,如
$data = $uid . '|' . $action . '|' . $timestamp) - 用服务端私有密钥(如
hash_hmac('sha256', $data, $secret_key))生成签名 - 客户端请求携带
timestamp和signature,服务端重新计算并比对
时间有效性判断:宽限窗口 + 单次使用(可选)
PHP 7.1 中建议设置 300 秒(5 分钟)窗口,避免因客户端/服务端时钟偏差导致误拒:
- 获取当前时间
$now = time(); - 解析请求中时间戳
$ts = (int) $_GET['timestamp'] ?? 0;(务必强制转 int,防字符串注入) - 检查是否在合理范围内:
if ($ts $now + 300) { die('Invalid timestamp'); } - 进阶:结合 Redis 或数据库记录已用时间戳(+ 用户 ID),拒绝重复
timestamp(适用于高敏感操作)
完整示例函数(含签名验证)
以下是一个轻量、可直接使用的校验函数(假设使用 GET 参数,实际中请适配 POST/JSON):
立即学习“PHP免费学习笔记(深入)”;
function verifyTimestampRequest($secretKey, $allowedSkew = 300) {
$ts = (int)($_GET['timestamp'] ?? 0);
$sig = $_GET['signature'] ?? '';
$uid = (string)($_GET['uid'] ?? '');
$action = (string)($_GET['action'] ?? '');
<pre class='brush:php;toolbar:false;'>// 1. 时间有效性
$now = time();
if ($ts < $now - $allowedSkew || $ts > $now + $allowedSkew) {
return false;
}
// 2. 构造待签名数据(保持顺序 & 防空值干扰)
$data = $uid . '|' . $action . '|' . $ts;
// 3. 生成期望签名(PHP 7.1 支持 hash_hmac)
$expectedSig = hash_hmac('sha256', $data, $secretKey);
// 4. 安全比对(防时序攻击)
return hash_equals($expectedSig, $sig);}
// 使用: if (!verifyTimestampRequest('my_secret_123')) { http_response_code(401); exit('Unauthorized'); }
注意事项(PHP 7.1 特别提醒)
-
禁用
register_globals(PHP 7.1 已移除,但确认配置无遗留风险) - 务必使用
hash_equals()做签名比对——它恒定时间,防侧信道攻击;切勿用==或=== - 时间戳字段名统一(如全用
timestamp),避免大小写混淆($_GET['Timestamp']在某些服务器上可能不生效) - 若需更高精度,可用
(int)round(microtime(true)),但需前后端约定单位,且注意整数溢出(2038 年问题在 32 位系统仍存在)



















