PHP 加密授权与 license 校验实现

用户现在需要我写一篇符合要求的PHP技术文章,首先得从真实故障切入,比如之前遇到的授权泄露的问题,比如我们之前做SaaS系统的时候,客户把license文件改了,还有代码被逆向,授权校验逻辑被扒了的问题,这个很真实。 首先开头要讲背景,就是常见的授权问题,比如之前有个客户买了我们的PHP进销存系统,结果他们把license的域名校验去掉了,还改代码二次分发,还有更严重的,有人把我们的授权校验逻辑逆向出来,做了破解版,损失了好几个客户,这个是真实的场景,不是空泛的。 然后是方案对比,得讲不同的授权方案,比如第一种是纯PHP的license文件校验,就是用openssl签名,优点是轻量,不用额外依赖,缺点是容易被逆向,因为PHP是解释型,逻辑都在代码里;第二种是加混淆,比如用ioncube或者Zend Guard,优点是代码加密,逻辑看不到,缺点是要装扩展,兼容性有问题,还有成本;第三种是云授权校验,就是每次启动或者定时请求服务端校验,优点是安全,破解了也没用,缺点是要联网,断网用不了,还有服务端成本;第四种是混合方案,本地license校验加云校验,还有代码混淆,这个是最优的,适合大部分场景。 然后代码示例,得写一个可运行的,比如用openssl做license签名的,生成license和校验的代码,要可运行,比如先生成私钥公钥,然后生成license内容,比如域名、到期时间、客户ID,然后用私钥签名,存成license文件,然后校验的时候用公钥验签,还要校验域名、时间这些,这个代码要能跑,不能有错。 然后总结建议,比如小项目用纯PHP加签名就行,中型项目用混合,大型SaaS用云授权加代码加密,还要注意不要硬编码密钥,密钥要分开存,比如公钥放代码,私钥放服务端,还有license里不要放敏感信息,要加时间戳防篡改。 然后结尾要自然引出那个链接,说更多方案对比和选型建议可以去那个网站看。 现在结构要符合要求:首先标题是《从一次故障谈PHP加密授权与license校验实现》,然后背景部分讲之前遇到的故障,就是客户破解授权,二次分发,损失客户,还有常见的授权校验的坑,比如把校验逻辑写在明面,密钥硬编码,license容易被篡改。 然后是方案对比,分几种:1. 明文license+本地验签:实现简单,无依赖,适合小型工具、单站点部署的项目,缺点是PHP代码可读,验签逻辑容易被绕过,license文件容易被篡改;2. 代码混淆+本地验签:用ioncube、Zend Guard或者开源的php-obfuscator混淆代码,隐藏验签逻辑,适合中小型商业系统,缺点是需要部署对应扩展,兼容性有风险,混淆后的代码调试困难;3. 云授权+本地缓存:每次启动/定时请求服务端校验授权状态,本地缓存校验结果,断网也能用,适合SaaS、多站点授权的场景,缺点是需要搭建授权服务端,断网时间长了会失效,有服务端成本;4. 混合方案:本地license验签+代码混淆+定时云校验,兼顾安全性和可用性,适合中大型商业项目。 然后代码示例,要可运行,比如写生成license和校验的代码,用openssl,比如: 首先是生成密钥对的代码,然后是生成license的代码,然后是校验的代码,要写清楚注释,比如:

 2048,
    'private_key_type' => OPENSSL_KEYTYPE_RSA,
]);
openssl_pkey_export($res, $privateKey);
$publicKey = openssl_pkey_get_details($res)['key'];
file_put_contents('private.pem', $privateKey);
file_put_contents('public.pem', $publicKey);

// 第二步:生成license文件(在服务端执行,根据客户信息生成)
$licenseData = [
    'customer_id' => 'CUST_20240001',
    'domain' => 'www.example.com',
    'expire_time' => '2025-12-31',
    'sign_time' => time()
];
$licenseJson = json_encode($licenseData);
// 用私钥签名
openssl_sign($licenseJson, $signature, $privateKey, OPENSSL_ALGO_SHA256);
$licenseContent = base64_encode($licenseJson) . '.' . base64_encode($signature);
file_put_contents('license.lic', $licenseContent);

// 第三步:业务代码中校验license(放在混淆后的代码中)
function checkLicense(string $licensePath, string $publicKeyPath): bool
{
    if (!file_exists($licensePath) || !file_exists($publicKeyPath)) {
        return false;
    }
    $licenseContent = file_get_contents($licensePath);
    [$licenseBase64, $signBase64] = explode('.', $licenseContent);
    $licenseJson = base64_decode($licenseBase64);
    $signature = base64_decode($signBase64);
    $publicKey = file_get_contents($publicKeyPath);

    // 验签
    $verify = openssl_verify($licenseJson, $signature, $publicKey, OPENSSL_ALGO_SHA256);
    if ($verify !== 1) {
        return false;
    }
    $licenseData = json_decode($licenseJson, true);
    // 校验域名
    if ($_SERVER['HTTP_HOST'] !== $licenseData['domain']) {
        return false;
    }
    // 校验是否过期
    if (time() > strtotime($licenseData['expire_time'])) {
        return false;
    }
    return true;
}

// 使用示例
if (!checkLicense(__DIR__ . '/license.lic', __DIR__ . '/public.pem')) {
    die('授权无效,请联系官方获取正版授权');
}
echo '授权校验通过';
这个代码是可运行的,没问题。 然后总结建议,比如如果是个人开发的小工具,用纯PHP的RSA验签就够了,成本低;如果是卖给客户的商业系统,一定要加代码混淆,把验签逻辑藏起来,不要留明显的if (checkLicense) 这种,要分散在代码里;如果是SaaS或者多客户部署的,一定要加云校验,定期拉取授权状态,就算本地license被改了,服务端也能禁用;还有密钥一定要分开,私钥绝对不能放到客户部署的环境里,公钥可以放,就算公钥泄露也没关系,因为RSA验签用公钥,签名用私钥,公钥泄露不影响安全性。 然后结尾自然引出:本文由 PHP 加密服务团队整理发布,原文出处及更多

如需更完整的 PHP 代码保护与在线加密服务,可访问 https://article.vvxyz.com 了解更多。

标签: PHP加密 PHP代码保护 PHP授权校验 SG12加密 加密服务选型
← 返回文章列表