PHP 密钥管理系统简单实现

wen PHP项目 2

本文目录导读:

PHP 密钥管理系统简单实现

  1. 项目结构
  2. 数据库配置 (config/config.php)
  3. 数据库类 (src/Database.php)
  4. 加密工具类 (src/Crypto.php)
  5. 密钥管理器 (src/KeyManager.php)
  6. 审计日志类 (src/AuditLogger.php)
  7. 数据库schema (sql/schema.sql)
  8. API接口 (public/index.php)
  9. README文件 (README.md)
  10. API使用示例
  11. 安全注意事项
  12. 扩展建议
  13. 使用说明

我将为您实现一个基于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
  1. 设置主密钥环境变量:

    export MASTER_KEY='your_very_secret_master_key'
  2. 配置数据库连接: 编辑 config/config.php

  3. 启动服务:

    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"

安全注意事项

  1. 主密钥安全: 主密钥应存储在安全的环境中,不应硬编码在代码中
  2. 使用HTTPS: 生产环境应使用HTTPS
  3. 限制访问权限: 仅授权用户可访问API
  4. 定期轮换: 建议定期轮换密钥
  5. 监控审计日志: 定期检查审计日志以发现异常

扩展建议

  • 添加用户认证和授权
  • 实现密钥备份和恢复
  • 添加密钥使用统计分析
  • 实现自动密钥轮换
  • 添加Web界面

使用说明

  1. 设置环境变量

    export MASTER_KEY='your-secure-master-key'
  2. 初始化数据库:导入schema.sql

  3. 生成密钥:调用API生成新密钥

  4. 使用密钥:通过API获取使用密钥

  5. 监控管理:查看审计日志和密钥状态

这个系统提供了基本的密钥管理功能,包括生成、存储、加密、轮换和审计,您可以根据需要扩展功能,如添加多用户支持、更强的身份验证机制等。

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