商業軟體交付時,需確保「一個授權碼對應一台授權伺服器」,防止未授權複製部署。核心思路:採集伺服器唯一環境特徵生成「機器碼」,授權時綁定該機器碼,執行時驗證一致性。
<?php
function generate_machine_fingerprint() {
$components = [
'server_software' => $_SERVER['SERVER_SOFTWARE'] ?? '', // Apache/Nginx 版本
'server_name' => $_SERVER['SERVER_NAME'] ?? '', // 域名/主機名
'document_root' => $_SERVER['DOCUMENT_ROOT'] ?? '', // 專案根目錄
'server_admin' => $_SERVER['SERVER_ADMIN'] ?? '', // 管理員郵箱
'server_addr' => $_SERVER['SERVER_ADDR'] ?? '', // 伺服器 IP
'php_version' => PHP_VERSION, // PHP 版本
'php_os' => PHP_OS, // 作業系統
'script_path' => __FILE__, // 入口腳本路徑
// 進階:網卡 MAC、CPU 序號、硬碟 ID (需擴展/Shell 執行權限)
];
// 過濾空值,排序確保一致性
$filtered = array_filter($components);
ksort($filtered);
return hash('sha256', implode('|', $filtered));
}
<?php
require 'license_client.php';
$fingerprint = generate_machine_fingerprint();
echo "機器碼: $fingerprint\n";
// 將機器碼提供給軟體供應商
?>
<?php
// 供應商端簽發工具
function issue_license($fingerprint, $product, $expiry, $private_key_pem) {
$payload = [
'fingerprint' => $fingerprint,
'product' => $product,
'issued_at' => time(),
'expires_at' => strtotime($expiry),
'nonce' => random_bytes(16)
];
// 使用 RSA 簽名防止偽造
$data = base64_encode(json_encode($payload));
openssl_sign($data, $signature, $private_key_pem, OPENSSL_ALGO_SHA256);
return [
'license' => $data,
'signature' => base64_encode($signature)
];
}
<?php
function verify_license($license_data, $public_key_pem) {
$decoded = json_decode(base64_decode($license_data['license']), true);
// 1. 簽名驗證
if (!openssl_verify(
$license_data['license'],
base64_decode($license_data['signature']),
$public_key_pem,
OPENSSL_ALGO_SHA256
)) {
throw new Exception('授權檔簽名無效');
}
// 2. 時效驗證
if (time() > $decoded['expires_at']) {
throw new Exception('授權已過期');
}
// 3. 機器碼綁定驗證
$current_fp = generate_machine_fingerprint();
if (!hash_equals($current_fp, $decoded['fingerprint'])) {
throw new Exception('機器碼不匹配,疑似未授權環境');
}
return $decoded; // 可取得產品版本、功能模組等資訊
}
// 整合到應用入口
try {
$license = json_decode(file_get_contents(__DIR__ . '/license.json'), true);
$public_key = file_get_contents(__DIR__ . '/keys/public.pem');
$verified = verify_license($license, $public_key);
define('LICENSE_VALID', true);
define('LICENSE_PRODUCT', $verified['product']);
} catch (Exception $e) {
die('授權驗證失敗: ' . $e->getMessage());
}
?>
Docker/K8s 環境下 IP、檔案路徑可能變動,建議: