UnionAllied Social Branding
Voltar ao Terminal

IA vs Segurança (Parte 3): O Perigo do Cache Multi-Tenant .

Code Audit 05 Mar, 2026
Cover

O Coração do SaaS: Multi-Tenancy e Seus Riscos

Quando a busca por performance cria uma "chave mestra" para seus dados na mão de qualquer usuário.

No terceiro capítulo da nossa série, analisamos o arquivo db.php. Em sistemas SaaS modernos, onde cada cliente (Tenant) tem seu próprio banco de dados, o desafio é: como conectar ao banco certo de forma rápida sem sobrecarregar o banco mestre?

A IA tentou ser "esperta" e implementou um sistema de cache. A ideia é boa, mas a execução beira o amadorismo de segurança ao expor credenciais onde elas nunca deveriam estar.

O Erro Fatal: Credenciais na Sessão

A IA configurou o salvamento das credenciais do banco de dados (Host, Usuário e Senha) dentro da $_SESSION.

Por que é perigoso?

  • • Se o servidor salvar sessões em arquivos, as senhas do banco estão em texto puro no disco.
  • • Um ataque de Session Hijacking entrega o banco de dados de presente ao invasor.
  • • Facilita a escalada de privilégios.

Qual a solução?

Use um cache externo como Redis ou Memcached com criptografia, ou apenas cacheie o ID do tenant, buscando os dados sensíveis no Mestre quando necessário.

Pontos de Honra

Nem tudo é tragédia. A configuração do objeto PDO em si é impecável:

  • Desativação de Emulação: Previne ataques complexos de Injeção.
  • Charset Seguro: O uso de utf8mb4_unicode_ci evita falhas de codificação que podem ser exploradas.
Union Allied Team

Union Allied Team

Auditoria Finalizada

db.php
Read Only
<pre class="language-php"><code>
&lt;?php
// _config/db.php - [AUDITORIA] Arquitetura Multi-Tenant detectada.

if (session_status() === PHP_SESSION_NONE) {
    // [AUDITORIA] Boa prática: Nome de sessão dinâmico por Tenant.
    // Isso evita colisão de cookies entre clientes no mesmo domínio.
    $sessionName = 'SESS_SAAS_' . strtoupper(preg_replace('/[^a-zA-Z0-9]/', '', explode('.', $cleanDomain)[0]));
    session_name($sessionName);

    session_set_cookie_params([
        'httponly' => true, // [AUDITORIA] Essencial contra XSS.
        'samesite' => 'Lax'
    ]);
    session_start();
}

// ... (configurações omitidas)

if ($is_subdomain) {
    // --- BLINDAGEM DE PERFORMANCE (CACHE) ---
    // [AUDITORIA CRÍTICA] ALERTA VERMELHO! 
    // A IA decidiu guardar as CREDENCIAIS DO BANCO (user/pass) na $_SESSION.
    // Se um atacante sequestrar a sessão ou houver um vazamento de logs de sessão,
    // ele terá acesso direto ao banco de dados de cada cliente.
    if (isset($_SESSION['TENANT_CACHE']) && $_SESSION['TENANT_CACHE']['sub'] === $subdomain) {
        $tenant = $_SESSION['TENANT_CACHE'];
        $final_db_pass = $tenant['db_pass']; // NUNCA guarde senhas em texto puro na sessão!
    } else {
        try {
            // [AUDITORIA] Prepared Statements usados corretamente para buscar o Tenant.
            $stmt = $pdoMaster->prepare("SELECT db_host, db_name, db_user, db_pass, status FROM tenants WHERE subdominio = ? LIMIT 1");
            $stmt->execute([$subdomain]);
            $tenantData = $stmt->fetch(PDO::FETCH_ASSOC);

            // [AUDITORIA] Verificação de status 'ativo' antes de conectar. Correto.
            if ($tenantData && $tenantData['status'] === 'ativo') {
                $_SESSION['TENANT_CACHE'] = array_merge($tenantData, ['sub' => $subdomain]);
            }
        } catch (PDOException $e) {
            error_log("MASTER DB ERROR: " . $e->getMessage());
        }
    }
}

// --- 4. CONEXÃO FINAL ---
try {
    // [AUDITORIA] Configurações de PDO excelentes:
    // ATTR_EMULATE_PREPARES => false (Prevenção real de SQL Injection)
    // utf8mb4 => Suporte total a caracteres e emojis.
    $pdo = new PDO("mysql:host={$final_db_host};dbname={$final_db_name};charset=utf8mb4", $final_db_user, $final_db_pass, [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        PDO::ATTR_EMULATE_PREPARES => false
    ]);
} catch (PDOException $e) {
    // [AUDITORIA] Uso de error_log em vez de var_dump impede a exposição de caminhos do servidor.
}
?>
</code></pre>

AI Generated • Human Audited

Veredito da Auditoria

Risco Crítico

"A IA construiu um cofre blindado, mas deixou a combinação anotada em um post-it colado na porta (a sessão do usuário)."

Vulnerabilidades

  • Exposição de credenciais de DB em variáveis de sessão.
  • Persistência de dados sensíveis em texto puro no servidor.
Score de Segurança
4.0 /10
SYSTEM_LOGS / usr_input_stream
Live Feed
user@sys:~$
01 02 03

⚠ WARNING: Inputs are sanitized. No HTML allowed.

Timestamp
Payload / Message
_

System Buffer Empty

Waiting for input stream...

Total Logs: 0 Memory Usage: 0.04MB
Whatsapp
Valorizamos sua privacidade Utilizamos cookies para aprimorar sua experiência de navegação, exibir anúncios personalizados e analisar nosso tráfego. Ao clicar em "Aceitar Todos", você concorda com o uso de cookies. Leia nossa Política de Cookies.