A autenticação de dois fatores (2FA) tornou-se um requisito essencial para aplicações web modernas. Com o aumento de 300% nos ataques cibernéticos nos últimos dois anos, implementar camadas adicionais de segurança não é mais opcional. Este tutorial demonstra como integrar 2FA em um blog Django utilizando a biblioteca django-otp.

Instalação e Configuração Inicial

A biblioteca django-otp oferece suporte completo para tokens baseados em tempo (TOTP) e SMS. Para instalá-la, execute:

pip install django-otp qrcode[pil]

Adicione as aplicações necessárias ao seu arquivo settings.py:

INSTALLED_APPS = [
    \'django.contrib.admin\',
    \'django.contrib.auth\',
    \'django.contrib.contenttypes\',
    \'django.contrib.sessions\',
    \'django.contrib.messages\',
    \'django.contrib.staticfiles\',
    \'django_otp\',
    \'django_otp.plugins.otp_totp\',
    \'django_otp.plugins.otp_static\',
    # suas outras apps
]

MIDDLEWARE = [
    \'django_otp.middleware.OTPMiddleware\',
    # outros middlewares
]

Execute as migrações para criar as tabelas necessárias:

python manage.py migrate

Criando Views para Autenticação 2FA

Implemente uma view para configurar o dispositivo TOTP do usuário:

from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django_otp.plugins.otp_totp.models import TOTPDevice
from django.contrib import messages
import qrcode
from io import BytesIO
import base64

@login_required
def setup_2fa(request):
    user = request.user
    device = TOTPDevice.objects.filter(user=user, confirmed=True).first()
    
    if not device:
        device = TOTPDevice.objects.create(
            user=user,
            name=\'default\',
            confirmed=False
        )
    
    if request.method == \'POST\':
        token = request.POST.get(\'token\')
        if device.verify_token(token):
            device.confirmed = True
            device.save()
            messages.success(request, \'Autenticação de dois fatores ativada!\')
            return redirect(\'profile\')
        else:
            messages.error(request, \'Token inválido. Tente novamente.\')
    
    # Gerar QR Code
    qr_url = device.config_url
    qr = qrcode.QRCode(version=1, box_size=10, border=5)
    qr.add_data(qr_url)
    qr.make(fit=True)
    
    img = qr.make_image(fill_color="black", back_color="white")
    buffer = BytesIO()
    img.save(buffer, format=\'PNG\')
    qr_image = base64.b64encode(buffer.getvalue()).decode()
    
    return render(request, \'setup_2fa.html\', {
        \'qr_image\': qr_image,
        \'secret_key\': device.key
    })

View de Verificação do Token

Crie uma view para verificar o token OTP durante o login:

from django_otp.decorators import otp_required
from django_otp import match_token

def verify_2fa(request):
    if request.method == \'POST\':
        token = request.POST.get(\'token\')
        user = request.user
        
        device = match_token(user, token)
        if device:
            request.session[\'2fa_verified\'] = True
            return redirect(\'dashboard\')
        else:
            messages.error(request, \'Código de verificação inválido\')
    
    return render(request, \'verify_2fa.html\')

Protegendo Views com 2FA

Use o decorador @otp_required para proteger views sensíveis:

from django_otp.decorators import otp_required

@login_required
@otp_required
def admin_panel(request):
    return render(request, \'admin_panel.html\')

@login_required
@otp_required
def financial_data(request):
    # Dados financeiros sensíveis
    return render(request, \'financial.html\')

Configurações de Segurança Avançadas

Para maximizar a segurança, configure estas opções no settings.py:

# Configurações OTP
OTP_TOTP_ISSUER = \'Seu Blog Django\'
OTP_LOGIN_URL = \'/auth/login/\'

# Configurações de sessão
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_SSL_REDIRECT = True

# Tempo de vida do token
OTP_TOTP_TOLERANCE = 1  # Aceita tokens com diferença de 30s

Backup Tokens

Implemente tokens de backup para casos de emergência:

from django_otp.plugins.otp_static.models import StaticDevice, StaticToken
import secrets

def generate_backup_tokens(user, count=10):
    device, created = StaticDevice.objects.get_or_create(
        user=user,
        name=\'backup\'
    )
    
    # Limpar tokens existentes
    device.token_set.all().delete()
    
    tokens = []
    for _ in range(count):
        token = secrets.token_hex(4).upper()
        StaticToken.objects.create(device=device, token=token)
        tokens.append(token)
    
    return tokens

Templates HTML

Crie o template setup_2fa.html:

{% extends \'base.html\' %}

{% block content %}

Configurar Autenticação de Dois Fatores

Escaneie o código QR com seu aplicativo autenticador:

QR Code

Ou digite manualmente a chave secreta:

{{ secret_key }}
{% csrf_token %}
{% endblock %}

Testes e Validação

Crie testes unitários para validar a implementação:

from django.test import TestCase
from django.contrib.auth.models import User
from django_otp.plugins.otp_totp.models import TOTPDevice

class TwoFactorAuthTest(TestCase):
    def setUp(self):
        self.user = User.objects.create_user(
            username=\'testuser\',
            password=\'testpass123\'
        )
        self.device = TOTPDevice.objects.create(
            user=self.user,
            name=\'default\',
            confirmed=True
        )
    
    def test_token_verification(self):
        token = self.device.token()
        self.assertTrue(self.device.verify_token(token))
    
    def test_invalid_token(self):
        self.assertFalse(self.device.verify_token(\'000000\'))

Implantação e Monitoramento

Para implantação segura, considere utilizar servidores VPS seguros que oferecem isolamento adequado para aplicações Django. Configure logs para monitorar tentativas de autenticação:

import logging

logger = logging.getLogger(\'django_otp\')

# No settings.py
LOGGING = {
    \'version\': 1,
    \'handlers\': {
        \'file\': {
            \'level\': \'INFO\',
            \'class\': \'logging.FileHandler\',
            \'filename\': \'otp_logs.log\',
        },
    },
    \'loggers\': {
        \'django_otp\': {
            \'handlers\': [\'file\'],
            \'level\': \'INFO\',
        },
    },
}

Para aplicações críticas, implemente rate limiting para prevenir ataques de força bruta. A biblioteca django-ratelimit funciona bem com django-otp.

Considere também configurar uma VPN segura para proteger conexões administrativas ao servidor de produção.