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-jwtPara 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
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.
Comentários
0Inicie sessão para deixar um comentário
Iniciar sessãoSé el primero en comentar