A autenticação de dois fatores (2FA) representa uma barreira essencial contra ataques cibernéticos modernos. Estatísticas mostram que 99.9% dos ataques automatizados são bloqueados pela implementação correta de 2FA. Este tutorial demonstra como construir um sistema robusto em PHP.

Fundamentos da Autenticação de Dois Fatores

A 2FA combina dois elementos distintos:

  • Algo que você sabe: senha tradicional
  • Algo que você possui: smartphone ou token físico

O protocolo TOTP (Time-based One-Time Password) gera códigos únicos válidos por 30 segundos. Aplicações como Google Authenticator e Authy implementam este padrão RFC 6238.

Configuração do Ambiente de Desenvolvimento

Configure seu ambiente PHP com as seguintes dependências:

composer require robthree/twofactorauth
composer require firebase/php-jwt

Para projetos que demandam hospedagem confiável, certifique-se de escolher provedores que suportem extensões PHP modernas.

Estrutura do Banco de Dados

Crie a estrutura necessária para armazenar informações de 2FA:

CREATE TABLE users (
  id INT PRIMARY KEY AUTO_INCREMENT,
  email VARCHAR(255) UNIQUE NOT NULL,
  password_hash VARCHAR(255) NOT NULL,
  two_factor_secret VARCHAR(32) NULL,
  two_factor_enabled BOOLEAN DEFAULT FALSE,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE backup_codes (
  id INT PRIMARY KEY AUTO_INCREMENT,
  user_id INT NOT NULL,
  code VARCHAR(10) NOT NULL,
  used_at TIMESTAMP NULL,
  FOREIGN KEY (user_id) REFERENCES users(id)
);

Implementação Técnica Completa

Desenvolva uma classe dedicada para gerenciar operações 2FA:

tfa = new TwoFactorAuth(\'SeuApp\');
        $this->pdo = $pdo;
    }
    
    public function generateSecret($userId) {
        $secret = $this->tfa->createSecret();
        
        $stmt = $this->pdo->prepare(
            "UPDATE users SET two_factor_secret = ? WHERE id = ?"
        );
        $stmt->execute([hash(\'sha256\', $secret), $userId]);
        
        return $secret;
    }
    
    public function generateQRCode($userEmail, $secret) {
        return $this->tfa->getQRCodeImageAsDataUri(
            $userEmail, 
            $secret
        );
    }
    
    public function verifyCode($secret, $code) {
        return $this->tfa->verifyCode($secret, $code, 2);
    }
    
    public function enableTwoFactor($userId, $verificationCode, $secret) {
        if (!$this->verifyCode($secret, $verificationCode)) {
            throw new Exception(\'Código inválido\');
        }
        
        $stmt = $this->pdo->prepare(
            "UPDATE users SET two_factor_enabled = TRUE WHERE id = ?"
        );
        $stmt->execute([$userId]);
        
        $this->generateBackupCodes($userId);
        return true;
    }
    
    private function generateBackupCodes($userId) {
        $codes = [];
        for ($i = 0; $i < 10; $i++) {
            $code = strtoupper(bin2hex(random_bytes(5)));
            $codes[] = $code;
            
            $stmt = $this->pdo->prepare(
                "INSERT INTO backup_codes (user_id, code) VALUES (?, ?)"
            );
            $stmt->execute([$userId, password_hash($code, PASSWORD_DEFAULT)]);
        }
        return $codes;
    }
}

Sistema de Login com Verificação 2FA

Implemente o fluxo de autenticação considerando a verificação em duas etapas:

pdo = $pdo;
        $this->tfaManager = new TwoFactorManager($pdo);
    }
    
    public function login($email, $password) {
        $stmt = $this->pdo->prepare(
            "SELECT * FROM users WHERE email = ?"
        );
        $stmt->execute([$email]);
        $user = $stmt->fetch();
        
        if (!$user || !password_verify($password, $user[\'password_hash\'])) {
            return [\'success\' => false, \'message\' => \'Credenciais inválidas\'];
        }
        
        if ($user[\'two_factor_enabled\']) {
            $_SESSION[\'pre_auth_user_id\'] = $user[\'id\'];
            return [
                \'success\' => true, 
                \'requires_2fa\' => true,
                \'message\' => \'Digite o código do seu aplicativo autenticador\'
            ];
        }
        
        $this->completeLogin($user);
        return [\'success\' => true, \'requires_2fa\' => false];
    }
    
    public function verifyTwoFactor($code) {
        if (!isset($_SESSION[\'pre_auth_user_id\'])) {
            return [\'success\' => false, \'message\' => \'Sessão inválida\'];
        }
        
        $userId = $_SESSION[\'pre_auth_user_id\'];
        $stmt = $this->pdo->prepare(
            "SELECT two_factor_secret FROM users WHERE id = ?"
        );
        $stmt->execute([$userId]);
        $secret = $stmt->fetchColumn();
        
        if ($this->tfaManager->verifyCode($secret, $code)) {
            $stmt = $this->pdo->prepare("SELECT * FROM users WHERE id = ?");
            $stmt->execute([$userId]);
            $user = $stmt->fetch();
            
            $this->completeLogin($user);
            unset($_SESSION[\'pre_auth_user_id\']);
            
            return [\'success\' => true];
        }
        
        return [\'success\' => false, \'message\' => \'Código inválido\'];
    }
    
    private function completeLogin($user) {
        $_SESSION[\'user_id\'] = $user[\'id\'];
        $_SESSION[\'user_email\'] = $user[\'email\'];
    }
}

Melhores Práticas de Segurança

Implemente estas medidas adicionais para maximizar a proteção:

  • Rate Limiting: Limite tentativas de verificação para prevenir ataques de força bruta
  • Códigos de Backup: Forneça códigos únicos para recuperação de acesso
  • Logs de Segurança: Registre todas as tentativas de autenticação
  • Criptografia: Use hash seguro para armazenar secrets

Para projetos que exigem infraestrutura robusta, considere utilizar servidores VPS dedicados que oferecem maior controle sobre configurações de segurança.

Implementação de Rate Limiting

pdo->prepare(
            "SELECT COUNT(*) FROM login_attempts 
             WHERE identifier = ? AND created_at > DATE_SUB(NOW(), INTERVAL ? SECOND)"
        );
        $stmt->execute([$identifier, $timeWindow]);
        
        return $stmt->fetchColumn() < $maxAttempts;
    }
    
    public function logAttempt($identifier, $success) {
        $stmt = $this->pdo->prepare(
            "INSERT INTO login_attempts (identifier, success, created_at) VALUES (?, ?, NOW())"
        );
        $stmt->execute([$identifier, $success]);
    }
}

Interface do Usuário e Experiência

Crie interfaces intuitivas que guiem usuários através do processo de configuração:


Configurar Autenticação de Dois Fatores

QR Code

Escaneie com seu aplicativo autenticador

Monitoramento e Manutenção

Estabeleça rotinas de monitoramento para identificar tentativas suspeitas:

  • Monitore falhas consecutivas de verificação 2FA
  • Implemente alertas para logins de localizações incomuns
  • Revise periodicamente códigos de backup não utilizados
  • Mantenha logs detalhados de atividades de autenticação

A implementação correta de 2FA reduz significativamente riscos de segurança, protegendo tanto dados de usuários quanto a reputação da aplicação. Mantenha bibliotecas atualizadas e monitore constantemente por vulnerabilidades de segurança.