PHP 怎么PHP 动态密钥

wen PHP项目 1

本文目录导读:

PHP 怎么PHP 动态密钥

  1. 常见的动态密钥实现方式
  2. 最佳实践建议

我来帮你了解PHP动态密钥的实现方式,动态密钥通常用于增强API安全性的签名验证机制。

常见的动态密钥实现方式

基于时间戳的动态密钥

<?php
class DynamicKey {
    private static $secretKey = 'your-static-secret-key';
    /**
     * 生成动态密钥
     */
    public static function generateKey() {
        $timestamp = time();
        $nonce = bin2hex(random_bytes(16));
        // 使用HMAC-SHA256生成动态签名
        $signature = hash_hmac('sha256', $timestamp . $nonce, self::$secretKey);
        return [
            'timestamp' => $timestamp,
            'nonce' => $nonce,
            'signature' => $signature,
            'expire_time' => $timestamp + 300 // 5分钟有效期
        ];
    }
    /**
     * 验证动态密钥
     */
    public static function verifyKey($timestamp, $nonce, $signature) {
        // 检查时间是否过期
        if (time() - $timestamp > 300) {
            return false;
        }
        // 重新计算签名
        $expectedSign = hash_hmac('sha256', $timestamp . $nonce, self::$secretKey);
        // 使用hash_equals防止时序攻击
        return hash_equals($expectedSign, $signature);
    }
}
// 使用示例
$key = DynamicKey::generateKey();
echo "Generated Key: " . json_encode($key) . "\n";
// 验证
$isValid = DynamicKey::verifyKey($key['timestamp'], $key['nonce'], $key['signature']);
echo "Key valid: " . ($isValid ? 'true' : 'false');
?>

基于Token的动态密钥(JWT风格)

<?php
class TokenKey {
    private static $secret = 'your-secret-key';
    public static function generateToken($userId) {
        $header = base64_encode(json_encode([
            'typ' => 'JWT',
            'alg' => 'HS256'
        ]));
        $payload = base64_encode(json_encode([
            'user_id' => $userId,
            'iat' => time(),
            'exp' => time() + 3600,
            'jti' => bin2hex(random_bytes(16)) // 唯一标识
        ]));
        $signature = hash_hmac('sha256', "$header.$payload", self::$secret);
        return "$header.$payload.$signature";
    }
    public static function validateToken($token) {
        $parts = explode('.', $token);
        if (count($parts) != 3) return false;
        list($header, $payload, $signature) = $parts;
        // 验证签名
        $expectedSign = hash_hmac('sha256', "$header.$payload", self::$secret);
        if (!hash_equals($expectedSign, $signature)) {
            return false;
        }
        // 解析payload检查过期
        $data = json_decode(base64_decode($payload), true);
        if ($data['exp'] < time()) {
            return false;
        }
        return $data;
    }
}
// 使用
$token = TokenKey::generateToken(123);
echo "Token: $token\n";
$result = TokenKey::validateToken($token);
echo "Validation: " . ($result ? 'success' : 'failed') . "\n";
?>

带盐值(Salt)的动态密钥

<?php
class SaltedKey {
    private static $masterKey = 'master-key';
    /**
     * 生成动态密钥对
     */
    public static function generateKeyPair() {
        $salt = bin2hex(random_bytes(32));
        $privateKey = hash_pbkdf2('sha256', self::$masterKey, $salt, 10000, 32);
        $publicKey = hash('sha256', $privateKey . $salt);
        return [
            'private_key' => base64_encode($privateKey),
            'public_key' => base64_encode($publicKey),
            'salt' => base64_encode($salt),
            'created_at' => time()
        ];
    }
    /**
     * 验证密钥
     */
    public static function verifyKey($privateKey, $salt, $publicKey) {
        $privateKey = base64_decode($privateKey);
        $salt = base64_decode($salt);
        $computedPublic = hash('sha256', $privateKey . $salt);
        $expectedPublic = base64_decode($publicKey);
        return hash_equals($expectedPublic, $computedPublic);
    }
}
// 使用
$keyPair = SaltedKey::generateKeyPair();
echo "Key Pair: " . json_encode($keyPair) . "\n";
$isValid = SaltedKey::verifyKey($keyPair['private_key'], $keyPair['salt'], $keyPair['public_key']);
echo "Verification: " . ($isValid ? 'valid' : 'invalid') . "\n";
?>

完整的API认证系统

<?php
class ApiAuth {
    private $secretKey;
    private $keyStore = [];
    public function __construct($secretKey) {
        $this->secretKey = $secretKey;
    }
    /**
     * 生成请求签名
     */
    public function signRequest($method, $uri, $params = [], $timestamp = null) {
        $timestamp = $timestamp ?? time();
        $nonce = bin2hex(random_bytes(16));
        // 排序参数
        ksort($params);
        $paramString = http_build_query($params);
        // 构建签名数据
        $signData = implode("\n", [
            $method,
            $uri,
            $paramString,
            $timestamp,
            $nonce
        ]);
        $signature = hash_hmac('sha256', $signData, $this->secretKey);
        return [
            'X-Timestamp' => $timestamp,
            'X-Nonce' => $nonce,
            'X-Signature' => $signature
        ];
    }
    /**
     * 验证请求签名
     */
    public function verifyRequest($method, $uri, $params, $headers) {
        // 检查必要头信息
        $required = ['X-Timestamp', 'X-Nonce', 'X-Signature'];
        foreach ($required as $key) {
            if (!isset($headers[$key])) {
                return false;
            }
        }
        $timestamp = $headers['X-Timestamp'];
        $nonce = $headers['X-Nonce'];
        $signature = $headers['X-Signature'];
        // 检查时间戳(5分钟窗口)
        if (abs(time() - $timestamp) > 300) {
            return false;
        }
        // 检查nonce是否已使用(防止重放攻击)
        if ($this->isNonceUsed($nonce)) {
            return false;
        }
        // 重新计算签名
        ksort($params);
        $paramString = http_build_query($params);
        $signData = implode("\n", [
            $method,
            $uri,
            $paramString,
            $timestamp,
            $nonce
        ]);
        $expectedSign = hash_hmac('sha256', $signData, $this->secretKey);
        if (!hash_equals($expectedSign, $signature)) {
            return false;
        }
        // 标记nonce为已使用
        $this->markNonceUsed($nonce);
        return true;
    }
    private function isNonceUsed($nonce) {
        // 实际应用中可以使用Redis或数据库存储
        return isset($this->keyStore[$nonce]);
    }
    private function markNonceUsed($nonce) {
        $this->keyStore[$nonce] = time();
        // 清理超过5分钟的旧nonce
        foreach ($this->keyStore as $key => $time) {
            if (time() - $time > 300) {
                unset($this->keyStore[$key]);
            }
        }
    }
}
// 使用示例
$auth = new ApiAuth('your-secret-key');
// 客户端生成签名
$signature = $auth->signRequest('POST', '/api/data', [
    'name' => 'test',
    'value' => 123
]);
echo "Request Headers: " . json_encode($signature) . "\n";
// 服务端验证
$isValid = $auth->verifyRequest('POST', '/api/data', [
    'name' => 'test',
    'value' => 123
], $signature);
echo "Request valid: " . ($isValid ? 'true' : 'false');
?>

最佳实践建议

  1. 使用HTTPS:确保密钥传输安全
  2. 限制密钥有效期:通常5-10分钟
  3. 添加随机数(nonce):防止重放攻击
  4. 使用安全的随机数生成器random_bytes()openssl_random_pseudo_bytes()
  5. 时间戳校验:使用宽泛时间窗口(如300秒)

选择哪种方式取决于你的具体需求,简单的API验证可以使用时间戳方式,需要更高安全性建议使用JWT或完整签名系统。

抱歉,评论功能暂时关闭!