本文目录导读:

- 项目结构
- 数据库配置 (config/config.php)
- 数据库类 (src/Database.php)
- 加密工具类 (src/Crypto.php)
- 密钥管理器 (src/KeyManager.php)
- 审计日志类 (src/AuditLogger.php)
- 数据库schema (sql/schema.sql)
- API接口 (public/index.php)
- README文件 (README.md)
- API使用示例
- 安全注意事项
- 扩展建议
- 使用说明
我将为您实现一个基于PHP的简单密钥管理系统,包含密钥生成、存储、加密和轮换功能。
项目结构
key-management/
├── config/
│ └── config.php
├── src/
│ ├── Database.php
│ ├── Crypto.php
│ ├── KeyManager.php
│ └── AuditLogger.php
├── public/
│ └── index.php
├── sql/
│ └── schema.sql
└── README.md
数据库配置 (config/config.php)
<?php
return [
'database' => [
'host' => 'localhost',
'name' => 'key_manager',
'user' => 'root',
'pass' => '',
'charset' => 'utf8mb4'
],
'settings' => [
'key_length' => 32, // 256位密钥
'iv_length' => 16, // 128位IV
'hash_algorithm' => 'sha256',
'cipher_method' => 'AES-256-CBC',
'key_expiry_days' => 90,
'max_retry_attempts' => 3
],
'encryption' => [
'master_key_env' => 'MASTER_KEY', // 主密钥从环境变量获取
'key_prefix' => 'kms_'
]
];
数据库类 (src/Database.php)
<?php
class Database {
private static $instance = null;
private $connection;
private function __construct($config) {
try {
$dsn = "mysql:host={$config['host']};dbname={$config['name']};charset={$config['charset']}";
$this->connection = new PDO($dsn, $config['user'], $config['pass'], [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]);
} catch (PDOException $e) {
throw new Exception('Database connection failed: ' . $e->getMessage());
}
}
public static function getInstance() {
if (self::$instance === null) {
$config = require __DIR__ . '/../config/config.php';
self::$instance = new self($config['database']);
}
return self::$instance;
}
public function getConnection() {
return $this->connection;
}
public function execute($query, $params = []) {
$stmt = $this->connection->prepare($query);
$stmt->execute($params);
return $stmt;
}
public function fetchAll($query, $params = []) {
$stmt = $this->execute($query, $params);
return $stmt->fetchAll();
}
public function fetchOne($query, $params = []) {
$stmt = $this->execute($query, $params);
return $stmt->fetch();
}
}
加密工具类 (src/Crypto.php)
<?php
class Crypto {
private $cipher_method;
private $master_key;
private $iv_length;
public function __construct($config) {
$this->cipher_method = $config['settings']['cipher_method'];
$this->iv_length = $config['settings']['iv_length'];
// 从环境变量获取主密钥
$masterKeyEnv = getenv($config['encryption']['master_key_env']);
if (!$masterKeyEnv) {
throw new Exception('Master key not found in environment');
}
$this->master_key = hash('sha256', $masterKeyEnv, true);
}
// 加密数据
public function encrypt($data, $key) {
$iv = openssl_random_pseudo_bytes($this->iv_length);
$encrypted = openssl_encrypt(
$data,
$this->cipher_method,
$key,
OPENSSL_RAW_DATA,
$iv
);
if ($encrypted === false) {
throw new Exception('Encryption failed');
}
// 组合 IV 和加密数据
$encoded = base64_encode($iv . $encrypted);
return $encoded;
}
// 解密数据
public function decrypt($data, $key) {
$decoded = base64_decode($data);
$iv = substr($decoded, 0, $this->iv_length);
$encrypted = substr($decoded, $this->iv_length);
$decrypted = openssl_decrypt(
$encrypted,
$this->cipher_method,
$key,
OPENSSL_RAW_DATA,
$iv
);
if ($decrypted === false) {
throw new Exception('Decryption failed');
}
return $decrypted;
}
// 生成随机密钥
public function generateKey($length = 32) {
return random_bytes($length);
}
// 生成主密钥哈希
public function hashKey($key) {
return hash('sha256', $key);
}
// 为特定密钥生成唯一ID
public function generateKeyId() {
return bin2hex(random_bytes(16));
}
}
密钥管理器 (src/KeyManager.php)
<?php
require_once 'Database.php';
require_once 'Crypto.php';
class KeyManager {
private $db;
private $crypto;
private $config;
public function __construct() {
$this->config = require __DIR__ . '/../config/config.php';
$this->db = Database::getInstance();
$this->crypto = new Crypto($this->config);
}
// 生成新密钥
public function generateKey($name, $type = 'general', $expiryDays = null) {
// 生成密钥对
$key = $this->crypto->generateKey($this->config['settings']['key_length']);
$keyId = $this->crypto->generateKeyId();
// 使用主密钥派生密钥
$masterKey = $this->getMasterKey();
$encryptionKey = $this->deriveKey($keyId, $masterKey);
// 加密密钥
$encryptedKey = $this->crypto->encrypt($key, $encryptionKey);
// 计算过期时间
$expiryDays = $expiryDays ?: $this->config['settings']['key_expiry_days'];
$expiresAt = date('Y-m-d H:i:s', strtotime("+{$expiryDays} days"));
// 准备API密钥
$apiKey = $keyId . ':' . bin2hex($key);
$apiHash = $this->crypto->hashKey($apiKey);
try {
// 存储密钥元数据和加密内容
$sql = "INSERT INTO keys_registry
(key_id, name, type, encrypted_key, api_key_hash,
status, created_at, expires_at, last_used_at)
VALUES (?, ?, ?, ?, ?, 'active', NOW(), ?, NULL)";
$this->db->execute($sql, [
$keyId,
$name,
$type,
$encryptedKey,
$apiHash,
$expiresAt
]);
// 记录审计日志
$this->logAudit('key_generation', [
'key_id' => $keyId,
'name' => $name,
'type' => $type
]);
return [
'key_id' => $keyId,
'api_key' => $apiKey,
'name' => $name,
'expires_at' => $expiresAt
];
} catch (Exception $e) {
throw new Exception('Failed to generate key: ' . $e->getMessage());
}
}
// 获取密钥(通过API密钥)
public function getKey($apiKey) {
// 验证API密钥格式
if (!preg_match('/^([a-f0-9]+):([a-f0-9]+)$/', $apiKey, $matches)) {
throw new Exception('Invalid API key format');
}
$keyId = $matches[1];
$keyHash = $this->crypto->hashKey($apiKey);
// 查找密钥
$keyData = $this->db->fetchOne(
"SELECT * FROM keys_registry WHERE key_id = ? AND api_key_hash = ?",
[$keyId, $keyHash]
);
if (!$keyData) {
throw new Exception('Invalid API key');
}
// 检查密钥状态
if ($keyData['status'] !== 'active') {
throw new Exception('Key is not active');
}
// 检查是否过期
if (strtotime($keyData['expires_at']) < time()) {
$this->deactivateKey($keyId, 'expired');
throw new Exception('Key has expired');
}
// 解密密钥
$masterKey = $this->getMasterKey();
$encryptionKey = $this->deriveKey($keyId, $masterKey);
$decryptedKey = $this->crypto->decrypt($keyData['encrypted_key'], $encryptionKey);
// 更新最后使用时间
$this->db->execute(
"UPDATE keys_registry SET last_used_at = NOW(),
usage_count = usage_count + 1 WHERE key_id = ?",
[$keyId]
);
// 记录审计日志
$this->logAudit('key_access', ['key_id' => $keyId]);
return [
'key_id' => $keyId,
'name' => $keyData['name'],
'key' => bin2hex($decryptedKey),
'expires_at' => $keyData['expires_at']
];
}
// 轮换密钥
public function rotateKey($keyId) {
$keyData = $this->db->fetchOne(
"SELECT * FROM keys_registry WHERE key_id = ?",
[$keyId]
);
if (!$keyData) {
throw new Exception('Key not found');
}
// 创建新密钥
$newKey = $this->crypto->generateKey($this->config['settings']['key_length']);
$newEncryptedKey = $this->crypto->encrypt(
$newKey,
$this->deriveKey($keyId, $this->getMasterKey())
);
// 更新密钥内容
$this->db->execute(
"UPDATE keys_registry SET
encrypted_key = ?,
rotated_at = NOW(),
rotation_count = rotation_count + 1
WHERE key_id = ?",
[$newEncryptedKey, $keyId]
);
// 生成新的API密钥
$newApiKey = $keyId . ':' . bin2hex($newKey);
// 记录审计日志
$this->logAudit('key_rotation', ['key_id' => $keyId]);
return [
'key_id' => $keyId,
'api_key' => $newApiKey
];
}
// 撤销密钥
public function revokeKey($keyId, $reason = 'manual') {
$this->deactivateKey($keyId, 'revoked', $reason);
// 记录审计日志
$this->logAudit('key_revocation', [
'key_id' => $keyId,
'reason' => $reason
]);
return true;
}
// 列出所有密钥
public function listKeys($status = null) {
$query = "SELECT id, key_id, name, type, status,
created_at, expires_at, last_used_at, usage_count
FROM keys_registry";
$params = [];
if ($status) {
$query .= " WHERE status = ?";
$params[] = $status;
}
$query .= " ORDER BY created_at DESC";
return $this->db->fetchAll($query, $params);
}
// 检查密钥健康状况
public function checkHealth() {
$stats = $this->db->fetchOne(
"SELECT
COUNT(*) as total,
SUM(status = 'active') as active,
SUM(status = 'revoked') as revoked,
SUM(status = 'expired') as expired
FROM keys_registry"
);
return $stats;
}
// 派生加密密钥
private function deriveKey($keyId, $masterKey) {
return hash_hmac('sha256', $keyId, $masterKey, true);
}
// 获取主密钥
private function getMasterKey() {
$masterKeyEnv = getenv($this->config['encryption']['master_key_env']);
if (!$masterKeyEnv) {
throw new Exception('Master key not found');
}
return hash('sha256', $masterKeyEnv, true);
}
// 停用密钥
private function deactivateKey($keyId, $status, $reason = null) {
$this->db->execute(
"UPDATE keys_registry SET status = ?,
revoked_at = NOW(), revoke_reason = ? WHERE key_id = ?",
[$status, $reason, $keyId]
);
}
// 记录审计日志
private function logAudit($action, $details) {
$sql = "INSERT INTO audit_logs (action, details, ip_address, created_at)
VALUES (?, ?, ?, NOW())";
$this->db->execute($sql, [
$action,
json_encode($details),
$_SERVER['REMOTE_ADDR'] ?? '127.0.0.1'
]);
}
}
审计日志类 (src/AuditLogger.php)
<?php
class AuditLogger {
private $db;
public function __construct() {
$this->db = Database::getInstance();
}
public function log($action, $details, $user = null) {
$sql = "INSERT INTO audit_logs (action, details, user_name, ip_address, created_at)
VALUES (?, ?, ?, ?, NOW())";
return $this->db->execute($sql, [
$action,
json_encode($details),
$user ?? $_SESSION['user'] ?? null,
$_SERVER['REMOTE_ADDR'] ?? '127.0.0.1'
]);
}
public function getLogs($limit = 50) {
return $this->db->fetchAll(
"SELECT * FROM audit_logs ORDER BY created_at DESC LIMIT ?",
[$limit]
);
}
}
数据库schema (sql/schema.sql)
-- 创建数据库
CREATE DATABASE IF NOT EXISTS key_manager;
USE key_manager;
-- 密钥表
CREATE TABLE IF NOT EXISTS keys_registry (
id INT AUTO_INCREMENT PRIMARY KEY,
key_id VARCHAR(32) NOT NULL UNIQUE,
name VARCHAR(100) NOT NULL,
type VARCHAR(50) NOT NULL DEFAULT 'general',
encrypted_key TEXT NOT NULL,
api_key_hash VARCHAR(64) NOT NULL,
status ENUM('active', 'revoked', 'expired') NOT NULL DEFAULT 'active',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
expires_at DATETIME NULL,
last_used_at DATETIME NULL,
revoked_at DATETIME NULL,
rotated_at DATETIME NULL,
revoke_reason VARCHAR(200) NULL,
usage_count INT DEFAULT 0,
rotation_count INT DEFAULT 0,
INDEX idx_status (status),
INDEX idx_created (created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 审计日志表
CREATE TABLE IF NOT EXISTS audit_logs (
id INT AUTO_INCREMENT PRIMARY KEY,
action VARCHAR(50) NOT NULL,
details TEXT NULL,
user_name VARCHAR(50) NULL,
ip_address VARCHAR(45) NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
INDEX idx_action (action),
INDEX idx_created (created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 密钥使用历史表
CREATE TABLE IF NOT EXISTS key_usage_history (
id INT AUTO_INCREMENT PRIMARY KEY,
key_id VARCHAR(32) NOT NULL,
user_agent VARCHAR(255) NULL,
request_count INT DEFAULT 0,
last_accessed_at DATETIME NULL,
FOREIGN KEY (key_id) REFERENCES keys_registry(key_id),
INDEX idx_key_id (key_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
API接口 (public/index.php)
<?php
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
require_once '../src/KeyManager.php';
$keyManager = new KeyManager();
$method = $_SERVER['REQUEST_METHOD'];
$path = $_SERVER['PATH_INFO'] ?? '/';
// 简单路由
try {
switch ($method) {
case 'POST':
$action = $_GET['action'] ?? 'generate';
if ($action === 'generate') {
$data = json_decode(file_get_contents('php://input'), true);
$result = $keyManager->generateKey(
$data['name'] ?? 'default_key',
$data['type'] ?? 'general',
$data['expiry_days'] ?? null
);
echo json_encode(['success' => true, 'data' => $result]);
} else {
// 其他POST操作
}
break;
case 'GET':
$apiKey = $_GET['api_key'] ?? null;
if ($apiKey) {
$result = $keyManager->getKey($apiKey);
echo json_encode(['success' => true, 'data' => $result]);
} else {
$keys = $keyManager->listKeys($_GET['status'] ?? null);
echo json_encode(['success' => true, 'data' => $keys]);
}
break;
case 'DELETE':
$keyId = $_GET['key_id'] ?? null;
$result = $keyManager->revokeKey($keyId);
echo json_encode(['success' => true, 'message' => 'Key revoked']);
break;
default:
http_response_code(405);
echo json_encode(['success' => false, 'error' => 'Method not allowed']);
}
} catch (Exception $e) {
http_response_code(400);
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
}
README文件 (README.md)
# PHP Key Management System 一个简单但功能完整的密钥管理系统。 ## 功能特点 - ✅ 安全生成加密密钥 - ✅ 使用AES-256加密存储密钥 - ✅ 支持密钥轮换和撤销 - ✅ 完整的审计日志 - ✅ 密钥过期管理 - ✅ RESTful API接口 ## 安装指南 1. 导入数据库schema: ```bash mysql -u root -p < sql/schema.sql
-
设置主密钥环境变量:
export MASTER_KEY='your_very_secret_master_key'
-
配置数据库连接: 编辑
config/config.php -
启动服务:
php -S localhost:8000 -t public/
API使用示例
生成新密钥
curl -X POST "http://localhost:8000/?action=generate" \
-H "Content-Type: application/json" \
-d '{"name": "my-app-key", "type": "general"}'
获取密钥
curl "http://localhost:8000/?api_key=your_generated_api_key"
轮换密钥
curl -X PUT "http://localhost:8000/?action=rotate&key_id=your_key_id"
撤销密钥
curl -X DELETE "http://localhost:8000/?key_id=your_key_id"
安全注意事项
- 主密钥安全: 主密钥应存储在安全的环境中,不应硬编码在代码中
- 使用HTTPS: 生产环境应使用HTTPS
- 限制访问权限: 仅授权用户可访问API
- 定期轮换: 建议定期轮换密钥
- 监控审计日志: 定期检查审计日志以发现异常
扩展建议
- 添加用户认证和授权
- 实现密钥备份和恢复
- 添加密钥使用统计分析
- 实现自动密钥轮换
- 添加Web界面
使用说明
-
设置环境变量:
export MASTER_KEY='your-secure-master-key'
-
初始化数据库:导入schema.sql
-
生成密钥:调用API生成新密钥
-
使用密钥:通过API获取使用密钥
-
监控管理:查看审计日志和密钥状态
这个系统提供了基本的密钥管理功能,包括生成、存储、加密、轮换和审计,您可以根据需要扩展功能,如添加多用户支持、更强的身份验证机制等。