UnionAllied Social Branding
Voltar ao Terminal

IA vs. Segurança: O código gerado é seguro? .

Code Audit 17 Out, 2023
Cover

Você já deve ter visto o apocalipse no LinkedIn: "Programadores juniores estão gerando sistemas inteiros com IA e o vazamento de dados é questão de tempo". Mas será que isso é apenas protecionismo de mercado ou uma realidade técnica?

Na Union Insights, decidimos parar de supor e começar a testar. Pedimos para uma IA gerar um núcleo de autenticação SaaS (Multi-tenant) em PHP puro. Visualmente? Lindo. Código limpo. Moderno.

Mas passamos um pente fino. O resultado? A IA acertou onde muitos humanos erram, mas cometeu um erro silencioso que poderia custar a sua empresa.


Auditoria: O que a IA acertou?

🛡️

Blindagem de Cookies (10/10)

A configuração foi militar. httponly impede XSS. samesite: Lax impede CSRF. E ainda criou isolamento de Tenant por subdomínio.

🔒

Headers de Proteção (9/10)

Headers corretos (X-Frame-Options, etc) protegendo contra Clickjacking e MIME sniffing.

🕵️

Validação de User Agent (8/10)

Se o navegador mudar durante a sessão, o usuário é deslogado. Ótimo contra Session Hijacking.

A Zona de Perigo: Onde a IA falhou?

Aqui entra o argumento de que "você precisa saber o que está pedindo". Olhe para o código ao lado.

1. O "Kill Switch" desligado (Risco Alto)

A IA implementou a lógica perfeita para derrubar sessões duplicadas. O problema? A linha está comentada! (Veja o comentário // logoutAndRedirect no código).

O sistema percebe a invasão, mas não faz nada.

2. A Porta dos Fundos via URL (Risco Médio)

Olhe a linha if (!isset($_GET['ajax_check'])).

Se um atacante adicionar ?ajax_check=1 na URL, o sistema pula a verificação de segurança do banco. Nunca confie em parâmetros GET para segurança.

3. Tratamento de Erro Silencioso

O bloco catch apenas faz um log. Se o banco cair, o sistema entra em modo Fail-Open (permite acesso) ao invés de Fail-Closed (bloqueia).

Union Allied Team

Union Allied Team

Auditoria Finalizada

auth.php
Read Only
<?php
// auth.php - Núcleo de Segurança da Sessão (Multi-tenant Reforçado)

if (!defined('BASE_URL')) {
    require_once __DIR__ . '/db.php';
}

// --- 1. CONFIGURAÇÃO DE COOKIE INTELIGENTE ---
$currentDomain = $_SERVER['HTTP_HOST'];
$cleanDomain   = str_replace('www.', '', $currentDomain);

// Verifica se é localhost ou IP (ex: 127.0.0.1) para não quebrar o cookie
// Browsers modernos rejeitam cookies com 'domain' setado em localhost
$isLocalhost = ($cleanDomain === 'localhost' || filter_var($cleanDomain, FILTER_VALIDATE_IP));
$cookieDomain = $isLocalhost ? null : $cleanDomain; 

// Nome da sessão único por Tenant
$sessionName = 'SESS_SAAS_' . strtoupper(preg_replace('/[^a-zA-Z0-9]/', '', explode('.', $cleanDomain)[0]));
session_name($sessionName);

// Configuração segura dos parâmetros
session_set_cookie_params([
    'lifetime' => 0,
    'path'     => '/',
    'domain'   => $cookieDomain, 
    'secure'   => (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on'),
    'httponly' => true,
    'samesite' => 'Lax'
]);

// Só inicia se ainda não estiver ativa
if (session_status() === PHP_SESSION_NONE) {
    session_start();
}

// --- 2. CABEÇALHOS DE SEGURANÇA ---
if (!headers_sent()) {
    header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
    header('Pragma: no-cache');
    header('Expires: 0');
    header('X-Frame-Options: SAMEORIGIN');
    header('X-Content-Type-Options: nosniff');
}

// --- 3. CONFIGURAÇÕES DE TEMPO ---
define('INACTIVITY_LIMIT', 1800); 

// --- 4. FUNÇÃO PRINCIPAL ---
function requireLogin() {
    global $pdo; 
    if (!isset($pdo)) require_once __DIR__ . '/db.php'; 

    // 1. Validação Básica
    if (!isset($_SESSION['user']) || empty($_SESSION['user']['id'])) {
        logoutAndRedirect();
    }

    // 2. Timeout
    if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > INACTIVITY_LIMIT)) {
        logoutAndRedirect('expired=true');
    }
    $_SESSION['LAST_ACTIVITY'] = time();

    // 3. User Agent
    $ua = $_SERVER['HTTP_USER_AGENT'] ?? 'Unknown';
    if (!isset($_SESSION['USER_AGENT'])) {
        $_SESSION['USER_AGENT'] = $ua;
    } elseif ($_SESSION['USER_AGENT'] !== $ua) {
        logoutAndRedirect(); 
    }

    // 4. Single Session Check (Ajax skip para performance se necessário)
    // ⚠️ FALHA CRÍTICA AQUI ⚠️
    if (!isset($_GET['ajax_check'])) {
        try {
            $stmt = $pdo->prepare("SELECT session_token FROM users WHERE id = ?");
            $stmt->execute([$_SESSION['user']['id']]);
            $dbToken = $stmt->fetchColumn();

            // ⚠️ CÓDIGO COMENTADO - KILL SWITCH DESLIGADO ⚠️
            if ($dbToken && $dbToken !== session_id()) {
                // logoutAndRedirect('kicked=true'); 
            }
        } catch (Exception $e) {
            // Log silencioso
        }
    }
    
    // 5. Force Change Password
    if (isset($_SESSION['force_change']) && $_SESSION['force_change'] === true) {
        $scriptAtual = basename($_SERVER['PHP_SELF']);
        $permitidos = ['perfil.php', 'logout.php', 'update_password.php', 'save_perfil.php'];

        if (!in_array($scriptAtual, $permitidos)) {
            // Tratamento para API
            $isApiCall = (strpos($_SERVER['REQUEST_URI'], '/api/') !== false) || 
                         (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest');

            if ($isApiCall) {
                header('Content-Type: application/json');
                echo json_encode(['success' => false, 'error' => 'force_change', 'message' => 'Troca de senha obrigatória']);
                exit; 
            }

            header("Location: " . BASE_URL . "/pages/perfil.php?warning=force_change");
            exit;
        }
    }
}

// --- 5. LOGOUT ---
function logoutAndRedirect($query = '') {
    // 1. Limpa o array da sessão
    $_SESSION = [];
    // 2. Mata o Cookie da Sessão (Com configurações agressivas para garantir a exclusão)
    if (ini_get("session.use_cookies")) {
        $params = session_get_cookie_params();
        setcookie(session_name(), '', time() - 42000,
            $params["path"], $params["domain"],
            $params["secure"], $params["httponly"]
        );
        setcookie(session_name(), '', time() - 42000, '/');
    }
    // 3. Destrói a sessão no servidor
    session_destroy();
    
    $redirectUrl = BASE_URL . '/_auth/login.php';
    if (!empty($query)) {
        $connector = (strpos($redirectUrl, '?') !== false) ? '&' : '?';
        $redirectUrl .= $connector . $query;
    }
    
    header("Location: " . $redirectUrl);
    exit;
}
?>

AI Generated • Human Audited

Veredito da Auditoria

9.0
Código
9.5
Configs
4.0
Lógica
Nota Final: 7.0 (Aprovado com Ressalvas Graves)

🔧 Correção Cirúrgica

  • Descomente a linha 85: Faça a expulsão (logout) acontecer de verdade.
  • Remova o bypass via GET: Use verificação baseada em tempo (session timestamp) para performance, nunca input do usuário.
  • Implemente Fail-Closed: Se der Exception no banco, deslogue o usuário imediatamente.

No próximo post: login.php. Será que a IA protegeu contra Brute Force? Fique ligado.

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.