本文目录导读:

在 PHP 中实现动态密钥(Dynamic Key)通常有以下几种常见场景和实现方式:
基于时间戳的动态密钥(最常用)
<?php
class DynamicKeyGenerator {
/**
* 生成基于时间的动态密钥
* @param string $secret 您的密钥
* @param int $validPeriod 有效时间(秒)
* @return array
*/
public static function generate($secret, $validPeriod = 300) {
$timestamp = time();
// 时间窗口用于分组
$timeWindow = floor($timestamp / $validPeriod);
// 组合密钥
$dynamicKey = hash_hmac('sha256', $timeWindow, $secret);
return [
'key' => $dynamicKey,
'timestamp' => $timestamp,
'expires_at' => $timestamp + $validPeriod
];
}
/**
* 验证动态密钥
* @param string $key 待验证的密钥
* @param string $secret 服务器端密钥
* @param int $validPeriod 有效时间(秒)
* @return bool
*/
public static function verify($key, $secret, $validPeriod = 300) {
$current = floor(time() / $validPeriod);
// 检查当前和上一个时间窗口,防止边缘情况
for ($i = 0; $i >= -1; $i--) {
$timeWindow = $current + $i;
$computedKey = hash_hmac('sha256', $timeWindow, $secret);
if (hash_equals($computedKey, $key)) {
return true;
}
}
return false;
}
}
// 使用示例
$secret = 'your-secret-key';
$result = DynamicKeyGenerator::generate($secret, 300); // 5分钟有效
echo "动态密钥: " . $result['key'] . "\n";
echo "过期时间: " . date('Y-m-d H:i:s', $result['expires_at']) . "\n";
// 验证
$isValid = DynamicKeyGenerator::verify($result['key'], $secret, 300);
基于随机数和数据库的动态密钥
<?php
class SessionDynamicKey {
private $db;
public function __construct($pdo) {
$this->db = $pdo;
}
/**
* 生成并存储在数据库中的动态密钥
*/
public function create($userId, $validDays = 7) {
// 生成随机密钥
$key = bin2hex(random_bytes(32));
$expires = date('Y-m-d H:i:s', strtotime("+{$validDays} days"));
try {
$sql = "INSERT INTO api_keys (user_id, api_key, expires_at, created_at)
VALUES (?, ?, ?, NOW())";
$stmt = $this->db->prepare($sql);
$stmt->execute([$userId, $key, $expires]);
// 返回带前缀的动态密钥
return sprintf('%s.%s', $userId, $key);
} catch (PDOException $e) {
throw new Exception("密钥生成失败: " . $e->getMessage());
}
}
/**
* 验证数据库中的动态密钥
*/
public function validate($apiKey) {
$parts = explode('.', $apiKey);
if (count($parts) !== 2) {
return false;
}
list($userId, $key) = $parts;
$sql = "SELECT * FROM api_keys
WHERE user_id = ? AND api_key = ?
AND expires_at > NOW()
AND revoked = 0
LIMIT 1";
$stmt = $this->db->prepare($sql);
$stmt->execute([$userId, $key]);
return $stmt->fetch() !== false;
}
/**
* 吊销动态密钥
*/
public function revoke($userId, $apiKey) {
$sql = "UPDATE api_keys SET revoked = 1
WHERE user_id = ? AND api_key = ?";
$stmt = $this->db->prepare($sql);
return $stmt->execute([$userId, $apiKey]);
}
}
基于客户端-服务器交互的动态密钥(增强安全性)
<?php
class TwoWayDynamicKey {
private $secret;
private $algorithm = 'sha256';
public function __construct($secret) {
$this->secret = $secret;
}
/**
* 生成挑战码(客户端用)
*/
public function generateChallenge() {
return bin2hex(random_bytes(16));
}
/**
* 生成响应码(服务器计算)
* @param string $challenge 客户端发送的挑战码
* @param string $extraData 额外数据(如用户ID等)
*/
public function generateResponse($challenge, $extraData = '') {
$data = $challenge . $extraData . $this->secret;
return hash($this->algorithm, $data);
}
/**
* 完整的两步认证流程示例
*/
public function twoStepAuth($clientInfo, $serverChallenge = null) {
// 步骤1: 服务器发送挑战码
if (!$serverChallenge) {
$challenge = $this->generateChallenge();
return [
'status' => 'challenge',
'challenge' => $challenge,
'message' => '请使用该挑战码生成响应'
];
}
// 步骤2: 客户端收到挑战码后生成响应
$clientResponse = $this->generateResponse($serverChallenge, $clientInfo);
// 步骤3: 服务器验证响应
$expectedResponse = $this->generateResponse($serverChallenge, $clientInfo);
if (hash_equals($expectedResponse, $clientResponse)) {
// 生成最终的会话密钥
$sessionKey = $this->generateResponse($serverChallenge, 'SESSION');
return [
'status' => 'success',
'session_key' => $sessionKey,
'expires_in' => 3600
];
}
return [
'status' => 'error',
'message' => '响应验证失败'
];
}
}
// 使用示例
$dyn = new TwoWayDynamicKey('super-secret-key-2024');
$result = $dyn->twoStepAuth('user_123');
// 返回挑战码
// $result = ['status' => 'challenge', 'challenge' => '...']
前后端配合的完整示例
<?php
class DynamicApiGate {
private static $secret = "your-application-secret";
/**
* 前端页面生成动态密钥(每次请求不同)
*/
public static function getDynamicToken() {
$timestamp = time();
$nonce = bin2hex(random_bytes(8));
$data = $timestamp . $nonce;
return [
'token' => hash_hmac('sha256', $data, self::$secret),
'timestamp' => $timestamp,
'nonce' => $nonce
];
}
/**
* 后端验证动态密钥
*/
public static function verifyRequest($headers) {
$token = $headers['X-Dynamic-Token'] ?? '';
$timestamp = $headers['X-Timestamp'] ?? 0;
$nonce = $headers['X-Nonce'] ?? '';
// 检查时间戳是否过期(5分钟内)
if (abs(time() - $timestamp) > 300) {
return ['valid' => false, 'reason' => 'Token expired'];
}
// 检查nonce是否已使用(防止重放攻击)
if (self::isNonceUsed($nonce)) {
return ['valid' => false, 'reason' => 'Nonce already used'];
}
// 重新计算期望的token
$expected = hash_hmac('sha256', $timestamp . $nonce, self::$secret);
if (hash_equals($expected, $token)) {
self::storeNonce($nonce); // 存储已使用的nonce
return ['valid' => true];
}
return ['valid' => false, 'reason' => 'Invalid token'];
}
private static function isNonceUsed($nonce) {
// 可以使用Redis或数据库
// 这里简单使用文件缓存示例
$file = sys_get_temp_dir() . '/nonce_' . md5($nonce);
return file_exists($file);
}
private static function storeNonce($nonce) {
$file = sys_get_temp_dir() . '/nonce_' . md5($nonce);
file_put_contents($file, time());
}
}
// 前端获取token
$token = DynamicApiGate::getDynamicToken();
// 后端验证(在中间件中)
$result = DynamicApiGate::verifyRequest($_SERVER);
JWT(JSON Web Token)动态密钥
<?php
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
class JwtDynamicKey {
private static $secret = "your-jwt-secret";
private static $algorithm = 'HS256';
/**
* 生成JWT动态密钥
*/
public static function createToken($userId, $extraData = []) {
$issuedAt = time();
$expire = $issuedAt + 3600; // 1小时有效
$payload = array_merge($extraData, [
'user_id' => $userId,
'iat' => $issuedAt,
'exp' => $expire,
'jti' => bin2hex(random_bytes(8)) // 唯一标识
]);
return JWT::encode($payload, self::$secret, self::$algorithm);
}
/**
* 验证JWT动态密钥
*/
public static function verifyToken($jwt) {
try {
$decoded = JWT::decode($jwt, new Key(self::$secret, self::$algorithm));
return (array)$decoded;
} catch (Exception $e) {
return null;
}
}
/**
* 刷新动态密钥
*/
public static function refreshToken($oldJwt) {
$data = self::verifyToken($oldJwt);
if ($data && isset($data['user_id'])) {
return self::createToken($data['user_id']);
}
return null;
}
}
安全性建议
- 使用 HTTPS:确保数据在传输过程中的安全
- 密钥存储:不要将密钥硬编码,使用环境变量或配置文件
- 时间窗口:合理设置过期时间,避免过长或过短
- 防重放攻击:使用 nonce 或 timestamp 验证
- 速率限制:对失败尝试进行限制
- 定期更换:定期更新主密钥
这些实现可以根据您的具体需求进行选择和改进。
版权声明: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直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播