本文目录导读:

在PHP中,HMAC(Hash-based Message Authentication Code)主要通过 hash_hmac() 函数实现,以下是详细的使用指南:
基本语法
string hash_hmac ( string $algo , string $data , string $key [, bool $binary = false ] )
| 参数 | 说明 |
|---|---|
$algo |
哈希算法(如 'md5', 'sha1', 'sha256', 'sha512' 等) |
$data |
要计算的消息内容 |
$key |
密钥 |
$binary |
是否返回原始二进制输出(默认 false 返回十六进制字符串) |
常用示例
基础 HMAC-SHA256 签名
$message = "这是要签名的消息";
$secretKey = "my-secret-key-12345";
// 生成签名(十六进制输出)
$signature = hash_hmac('sha256', $message, $secretKey);
echo "签名: " . $signature . "\n";
// 生成签名(原始二进制输出)
$binarySignature = hash_hmac('sha256', $message, $secretKey, true);
echo "二进制签名 (base64): " . base64_encode($binarySignature);
API 签名验证示例
// 服务器端生成签名
function generateSignature($data, $secretKey) {
return hash_hmac('sha256', json_encode($data), $secretKey);
}
// 客户端验证签名
function verifySignature($data, $signature, $secretKey) {
$expected = generateSignature($data, $secretKey);
return hash_equals($expected, $signature); // 使用 hash_equals 防止时序攻击
}
// 使用示例
$payload = ['user_id' => 123, 'timestamp' => time()];
$key = 'api-secret-key-2024';
$signature = generateSignature($payload, $key);
echo "API 签名: " . $signature . "\n";
// 验证
$isValid = verifySignature($payload, $signature, $key);
echo "签名验证: " . ($isValid ? "通过" : "失败") . "\n";
带时间戳的 HMAC(防止重放攻击)
class HMACAuth {
private $secretKey;
private $timeout = 300; // 5分钟超时
public function __construct($secretKey) {
$this->secretKey = $secretKey;
}
public function generateToken($data) {
$timestamp = time();
$payload = json_encode([
'data' => $data,
'timestamp' => $timestamp
]);
$signature = hash_hmac('sha256', $payload, $this->secretKey);
return base64_encode(json_encode([
'payload' => $payload,
'signature' => $signature
]));
}
public function validateToken($token) {
$decoded = json_decode(base64_decode($token), true);
if (!$decoded || !isset($decoded['payload']) || !isset($decoded['signature'])) {
return false;
}
// 验证签名
$expectedSignature = hash_hmac('sha256', $decoded['payload'], $this->secretKey);
if (!hash_equals($expectedSignature, $decoded['signature'])) {
return false;
}
// 验证时间戳
$payload = json_decode($decoded['payload'], true);
$elapsed = time() - $payload['timestamp'];
if ($elapsed > $this->timeout) {
return false; // Token 过期
}
return $payload['data'];
}
}
// 使用示例
$auth = new HMACAuth('super-secret-key');
$token = $auth->generateToken(['user' => 'john_doe']);
echo "生成的 Token: " . $token . "\n";
$result = $auth->validateToken($token);
echo "验证结果: " . ($result ? "有效 - 用户: " . $result['user'] : "无效") . "\n";
HMAC 与不同的哈希算法
$data = "Hello, World!";
$key = "my-key";
$algorithms = ['md5', 'sha1', 'sha256', 'sha384', 'sha512', 'ripemd160'];
echo "各种 HMAC 算法对比:\n";
foreach ($algorithms as $algo) {
$signature = hash_hmac($algo, $data, $key);
echo str_pad($algo, 12) . ": " . $signature . "\n";
}
HMAC 签名
function signFile($filePath, $secretKey) {
$content = file_get_contents($filePath);
return hash_hmac('sha256', $content, $secretKey);
}
// 使用
$fileSignature = signFile('document.pdf', 'file-signing-key');
echo "文件签名: " . $fileSignature;
安全注意事项
时序攻击防护
永远使用 hash_equals() 进行比较,而不是 或 :
// 安全
if (hash_equals($expected, $provided)) {
// 验证通过
}
// 不安全 - 易受时序攻击
if ($expected === $provided) {
// 不推荐
}
密钥管理
// 推荐:使用环境变量或配置文件
$secretKey = getenv('API_SECRET_KEY');
// 或从安全配置读取
$config = require 'config.php';
$secretKey = $config['hmac_key'];
完整的 HMAC 工具类
class HMACTool {
/**
* 生成 HMAC 签名
*/
public static function sign($data, $key, $algo = 'sha256') {
return hash_hmac($algo, $data, $key);
}
/**
* 验证 HMAC 签名(安全比较)
*/
public static function verify($data, $signature, $key, $algo = 'sha256') {
$expected = self::sign($data, $key, $algo);
return hash_equals($expected, $signature);
}
/**
* 生成带签名的 URL
*/
public static function signUrl($url, $key, $expiry = 3600) {
$expiryTime = time() + $expiry;
$signature = self::sign($url . $expiryTime, $key);
return $url . (strpos($url, '?') === false ? '?' : '&')
. "expires={$expiryTime}&signature={$signature}";
}
/**
* 验证签名 URL
*/
public static function verifySignedUrl($url, $key) {
$parsedUrl = parse_url($url);
parse_str($parsedUrl['query'] ?? '', $params);
if (!isset($params['signature']) || !isset($params['expires'])) {
return false;
}
// 检查是否过期
if (time() > $params['expires']) {
return false;
}
// 重新构建 URL(去除签名参数)
$baseUrl = strtok($url, '?');
$queryParts = [];
foreach ($params as $k => $v) {
if ($k !== 'signature') {
$queryParts[] = "$k=$v";
}
}
$cleanUrl = $baseUrl . '?' . implode('&', $queryParts);
// 验证签名
return self::verify($cleanUrl . $params['expires'], $params['signature'], $key);
}
}
// 使用示例
$key = 'url-signing-key';
$url = 'https://api.example.com/download/file123';
$signedUrl = HMACTool::signUrl($url, $key, 3600);
echo "签名URL: " . $signedUrl . "\n";
// 验证
$isValid = HMACTool::verifySignedUrl($signedUrl, $key);
echo "URL有效: " . ($isValid ? "是" : "否");
- 算法选择:优先使用
sha256或sha512,避免使用 MD5 或 SHA1 - 密钥强度:使用足够长且随机的密钥(至少 32 字节)
- 比较方式:始终使用
hash_equals()进行比较 - 密钥存储:不要在代码中硬编码密钥
- 时效性:为签名添加时间戳以防止重放攻击
HMAC 在 API 认证、JWT 实现、Webhook 验证等场景中非常常用,掌握这些用法对 PHP 开发很有帮助。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播