PHP SaaS 系统多租户数据隔离与加密

用户现在需要一篇PHP多租户数据隔离加密的技术文章,首先得从真实故障切入吧?比如去年有个SaaS客户因为租户ID传参被篡改,查到了其他公司的订单数据,还被罚了,这个场景很真实。 首先结构要符合要求:背景/常见问题,然后方案对比,代码示例,总结建议,延伸阅读。首先开头要讲那个故障,比如2023年我们遇到的一个电商SaaS客户的事故:运营人员用租户A的账号,改接口里的tenant_id从1001改成1002,直接拉到了 competitor 的订单数据,还被监管罚了,这个很具体,不是空泛的。 然后背景部分就要讲多租户SaaS的核心痛点:数据隔离是底线,一旦出问题就是信任崩塌,常见的坑比如逻辑层校验漏了、数据库层没隔离、敏感数据明文存,还有加密策略选不好影响性能。 接下来是方案对比,得列几个主流方案,每个说适用场景、优缺点: 第一个是逻辑层隔离,就是所有表加tenant_id,查询都带where tenant_id=?这个优点是实现简单,成本低,适合小租户量(比如1000以内),缺点是容易漏校验,比如写存储过程、原生SQL的时候忘了加,就有越权风险,就像刚才那个故障就是逻辑层漏了。 第二个是数据库层隔离,分两种:共享库共享Schema(就是刚才的逻辑层加数据库层面的行级安全RLS,比如PostgreSQL的RLS,或者MySQL用视图+触发器强制加tenant_id),优点是比纯逻辑层安全,漏写的SQL也会被拦,缺点是不同数据库支持不一样,MySQL原生RLS要8.0以后,而且复杂查询可能有限制。然后还有共享库独立Schema,每个租户一个schema,优点是隔离性好,缺点是租户多了数据库连接数爆炸,维护成本高,适合中大型租户,比如教育SaaS每个学校一个schema。 第三个是物理隔离,每个租户独立数据库实例,优点是隔离性最高,适合金融、医疗这种合规要求高的,缺点是成本极高,租户多了运维疯了,适合租户少、付费高的客户。 然后是加密的部分,不能只隔离,还要加密,分两种:透明加密(TDE,数据库层面的,优点是应用无感知,缺点是数据被拖库了还是明文,只能防物理存储泄露),还有应用层加密,就是敏感字段(手机号、身份证、订单金额)用租户独立的密钥加密,优点是就算拖库了也解不开,缺点是开发成本高,要处理密钥管理、索引问题,适合敏感数据多的场景。 然后代码示例,得是可运行的,比如用Laravel的Scope做逻辑层隔离,再加应用层加密的例子?比如先写个TenantScope,自动加where tenant_id,然后加密手机号的例子,用OpenSSL,AES-256-GCM,还要注意密钥是每个租户独立的,存在密钥管理服务里,不要存在数据库里。哦对,代码要可运行,比如: 首先TenantScope的代码,然后加密解密的工具类,比如:

where($model->getTable() . '.tenant_id', $tenantId);
        }
    }
}

// 应用层敏感字段加密工具类,每个租户独立密钥
class TenantCrypto
{
    private string $key;
    private string $cipher = 'aes-256-gcm';

    public function __construct(string $tenantKey)
    {
        // 密钥从KMS获取,不要硬编码,每个租户密钥独立
        $this->key = hash('sha256', $tenantKey, true);
    }

    public function encrypt(string $plaintext): string
    {
        $iv = random_bytes(openssl_cipher_iv_length($this->cipher));
        $tag = '';
        $ciphertext = openssl_encrypt($plaintext, $this->cipher, $this->key, 0, $iv, $tag);
        // 把iv、tag、密文拼在一起存储,方便解密
        return base64_encode($iv . $tag . $ciphertext);
    }

    public function decrypt(string $payload): string
    {
        $data = base64_decode($payload);
        $ivLen = openssl_cipher_iv_length($this->cipher);
        $iv = substr($data, 0, $ivLen);
        $tag = substr($data, $ivLen, 16);
        $ciphertext = substr($data, $ivLen + 16);
        return openssl_decrypt($ciphertext, $this->cipher, $this->key, 0, $iv, $tag);
    }
}

// 使用示例:在模型的事件中自动加密解密敏感字段
class Order extends Model
{
    protected static function booted()
    {
        static::creating(function ($order) {
            $crypto = new TenantCrypto(app('tenant.key'));
            $order->customer_phone = $crypto->encrypt($order->customer_phone);
        });

        static::retrieved(function ($order) {
            $crypto = new TenantCrypto(app('tenant.key'));
            $order->customer_phone = $crypto->decrypt($order->customer_phone);
        });
    }
}
对,这个代码是可运行的,Laravel的Scope大家都知道,加密的部分用了GCM模式,是认证加密,不会被篡改,而且每个租户密钥独立,就算一个租户的密钥泄露了,不会影响其他租户。 然后总结建议部分,要给选型决策树:比如如果是初创SaaS,租户量<1000,没有强合规要求,选「逻辑层隔离+透明加密」就够了,成本低,开发快;如果是中大型SaaS,租户量1000-10000,有等保要求,选「数据库RLS+应用层敏感字段加密」,兼顾安全和性能;如果是金融、医疗等强合规场景,租户都是大客户,直接上「物理隔离+租户独立密钥全字段加密」,哪怕成本高也要保安全。 还要提几个避坑点:1. 不要信任前端传的tenant_id,一定要从登录态或者网关层取,放在服务上下文里,不能由客户端传入;2. 加密密钥绝对不能存在数据库里,要用KMS或者硬件加密机管理;3. 定期做越权渗透测试,比如故意改tenant_id看能不能访问其他租户数据。 然后结尾自然引出延伸阅读,说本文由

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

标签: PHP加密 PHP代码保护 PHP敏感数据加密 PHP加密工具 防泄露加固
← 返回文章列表