php实现url签名
实现URL签名的基本步骤
生成URL签名可以确保URL的完整性和安全性,防止篡改。以下是PHP实现URL签名的基本方法:
准备URL参数
将需要签名的URL参数按照字母顺序排序,确保签名的一致性。使用http_build_query函数将参数转换为字符串。
$params = [
'param1' => 'value1',
'param2' => 'value2',
'timestamp' => time()
];
ksort($params);
$queryString = http_build_query($params);
生成签名 使用HMAC算法(如SHA256)和密钥对参数字符串进行签名。密钥应妥善保管,避免泄露。
$secretKey = 'your_secret_key';
$signature = hash_hmac('sha256', $queryString, $secretKey);
将签名附加到URL 将生成的签名作为参数附加到原始URL中,确保接收方可以验证签名。
$params['signature'] = $signature;
$signedUrl = 'http://example.com/api?' . http_build_query($params);
验证URL签名的方法
接收方需要验证URL签名的有效性,确保请求未被篡改。
提取签名 从URL参数中提取签名,并移除签名参数以便重新生成签名进行比对。
$receivedSignature = $_GET['signature'];
unset($_GET['signature']);
重新生成签名 使用相同的密钥和参数重新生成签名,与接收到的签名进行比对。
ksort($_GET);
$queryString = http_build_query($_GET);
$expectedSignature = hash_hmac('sha256', $queryString, $secretKey);
验证签名 比较接收到的签名和重新生成的签名是否一致,不一致则说明URL可能被篡改。
if (hash_equals($expectedSignature, $receivedSignature)) {
echo '签名验证通过';
} else {
echo '签名验证失败';
}
增强安全性的建议
添加时间戳 在URL参数中加入时间戳,可以防止重放攻击。验证时检查时间戳是否在有效范围内。
$timestamp = $_GET['timestamp'];
if (time() - $timestamp > 300) { // 5分钟有效期
echo '请求已过期';
}
使用一次性随机数 为每次请求生成唯一的随机数(nonce),确保同一请求不会被重复使用。
$nonce = bin2hex(random_bytes(16));
$params['nonce'] = $nonce;
限制签名有效期 通过设置签名有效期,减少被截获后利用的风险。验证时检查时间戳是否在合理范围内。
if (abs(time() - $timestamp) > 300) {
echo '请求已过期';
}
完整示例代码
以下是一个完整的URL签名生成和验证的示例代码:
生成签名URL
$params = [
'param1' => 'value1',
'param2' => 'value2',
'timestamp' => time(),
'nonce' => bin2hex(random_bytes(16))
];
ksort($params);
$queryString = http_build_query($params);
$secretKey = 'your_secret_key';
$signature = hash_hmac('sha256', $queryString, $secretKey);
$params['signature'] = $signature;
$signedUrl = 'http://example.com/api?' . http_build_query($params);
验证签名URL
$receivedSignature = $_GET['signature'];
unset($_GET['signature']);
ksort($_GET);
$queryString = http_build_query($_GET);
$expectedSignature = hash_hmac('sha256', $queryString, $secretKey);
if (!hash_equals($expectedSignature, $receivedSignature)) {
die('签名验证失败');
}
if (abs(time() - $_GET['timestamp']) > 300) {
die('请求已过期');
}
echo '签名验证通过';






