Django es un excelente marco con características de seguridad integradas. Sin embargo, muchos desarrolladores, especialmente en las primeras etapas de un proyecto, cometen el error de dejar la URL /admin tal como la crean siguiendo la documentación oficial o tutoriales.
Esto es como poner un gran cartel que dice "¡La puerta principal de mi casa está aquí!". Los escáneres y bots de ataque automatizados de todo el mundo son los primeros en escanear example.com/admin/ cuando descubren un sitio web.
En este artículo, presentaremos algunas formas clave de proteger de manera segura la página de administración de Django, desde el simple cambio de URL hasta la bloqueación activa de IPs de intrusos, explicando el por qué de cada método.
1. La más básica: Cambiar la URL del administrador (usando variables de entorno)
Es la primera línea de defensa más fácil, rápida y efectiva.
🤔 QUÉ: ¿Por qué ocultar la URL?
Un atacante no puede intentar un ataque de fuerza bruta o robo de credenciales si no conoce la URL. Usar una ruta que nadie pueda adivinar, como my-super-secret-admin-path/ en lugar de la conocida /admin, puede bloquear el 99% de los ataques automatizados.
Si bien 'ocultar' no es todo lo que hay en 'seguridad', es la defensa más efectiva en términos de costo.
🚀 CÓMO: Inyección a través de variables de entorno
Es una buena práctica inyectar la URL mediante variables de entorno en lugar de hardcodearla en el código.
- Archivo .env (o configuración de variables de entorno del servidor)
# .env
# Usa una cadena compleja que nadie pueda adivinar.
DJANGO_ADMIN_URL=my-secret-admin-portal-b7x9z/
- settings.py
# settings.py
import os
# Configura un valor predeterminado, pero lee de la variable de entorno
ADMIN_URL = os.environ.get('DJANGO_ADMIN_URL', 'admin/')
- urls.py (proyecto principal)
# urls.py
from django.contrib import admin
from django.urls import path
from django.conf import settings # importando el módulo settings
urlpatterns = [
# usando settings.ADMIN_URL en lugar de admin/
path(settings.ADMIN_URL, admin.site.urls),
# ... otras urls
]
Ahora, en el entorno de desarrollo se puede usar admin/, pero en el servidor de producción solo se cambia la variable de entorno para ocultar la verdadera ruta de administración.
2. Fortaleciendo: Restringir el acceso por IP en Nginx
Incluso si la URL se expone, es una forma efectiva de bloquear el acceso a la página de administración si no es desde una IP permitida.
🤔 QUÉ: ¿Por qué bloquear en Nginx?
Este método bloquea el tráfico de ataque en el servidor web (Nginx) antes de que llegue a Django (la aplicación). Es decir, Django ni siquiera se entera de que hubo un intento de ataque y no desperdicia recursos innecesarios. Si el administrador accede solo desde IPs específicas (oficina, VPN, etc.), este es el método más seguro.
CÓMO: Ejemplo de configuración de Nginx
Agrega un bloque location en el archivo de configuración de Nginx (en la configuración del sitio dentro de sites-available).
server {
# ... (configuración existente)
# Especifica la ruta que es igual a la variable de entorno ADMIN_URL
location /my-secret-admin-portal-b7x9z/ {
# 1. Dirección IP permitida (por ejemplo, IP fija de oficina)
allow 192.168.0.10;
# 2. Rango de IP permitidas (por ejemplo, rango de VPN)
allow 10.0.0.0/24;
# 3. localhost (interno del servidor)
allow 127.0.0.1;
# 4. Bloquea todo acceso que no sea el de las IPs anteriores
deny all;
# 5. Pasando todas las solicitudes a uwsgi/gunicorn
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
}
# ... (otras configuraciones de location)
}
Ahora, cualquier usuario que no tenga una IP permitida no recibirá respuesta de Django, y Nginx devolverá inmediatamente un error 403 Forbidden.
3. Colocar un guardia: Limitar intentos de inicio de sesión (django-axes)
Si un atacante ha averiguado la URL y ha eludido la restricción de IP, ahora se debe prevenir el ataque de fuerza bruta.
🤔 QUÉ: ¿Por qué limitar los intentos?
Los ataques de fuerza bruta intentan de manera automática introducir miles o decenas de miles de contraseñas para cuentas comunes como 'admin'. Un paquete como django-axes puede crear reglas como "si hay más de 5 intentos fallidos de inicio de sesión en poco tiempo, bloquea esa IP o cuenta por un tiempo determinado".
Esto hace que los scripts automatizados sean prácticamente inútiles.
CÓMO: Usar django-axes
django-axes es el paquete estándar para esta tarea.
-
Instalación:
pip install django-axes -
Registro en settings.py:
INSTALLED_APPS = [
# ...
'axes', # se recomienda ponerlo antes que otras apps
# ...
'django.contrib.admin',
]
AUTHENTICATION_BACKENDS = [
# AxesBackend debe estar primero.
'axes.backends.AxesBackend',
# Backend de autenticación estándar de Django
'django.contrib.auth.backends.ModelBackend',
]
# Bloqueo por 10 minutos tras 5 fallos (valor predeterminado)
AXES_FAILURE_LIMIT = 5
AXES_COOLOFF_TIME = 0.166 # 0.166 * 60 = alrededor de 10 minutos
- Migración:
python manage.py migrate
Ahora, si alguien falla 5 veces seguidas al intentar iniciar sesión, axes registrará ese intento y bloqueará los inicios de sesión de esa IP/cuenta durante el tiempo especificado.
4. Doble cerradura: Autenticación de dos pasos (2FA)
Es la última línea de defensa en caso de que la contraseña se vea comprometida.
🤔 QUÉ: ¿Por qué se necesita 2FA?
La contraseña de la cuenta de administrador podría haberse filtrado o ser demasiado simple. La autenticación de dos factores requiere "algo que sé (la contraseña)" y "algo que tengo (OTP del teléfono inteligente)".
Incluso si un hacker roba la contraseña, nunca podrá iniciar sesión sin el teléfono del administrador.
CÓMO: Usar django-otp
django-otp es el paquete clave que integra 2FA en Django.
-
Instalación:
pip install django-otp -
Registro en settings.py:
INSTALLED_APPS = [
# ...
'django_otp',
'django_otp.plugins.otp_totp', # compatible con Google Authenticator y otros
# ...
]
MIDDLEWARE = [
# ...
'django_otp.middleware.OTPMiddleware', # después de SessionMiddleware
# ...
]
django-otp es el esqueleto básico y, si se usa junto con un paquete como django-two-factor-auth, permite a los usuarios escanear y registrar fácilmente un código QR.
5. Crear trampas: Honeypot y Fail2Ban
Es la defensa más proactiva. Aprovecha los intentos de escaneo de /admin de los atacantes para expulsarlos permanentemente del servidor.
🤔 QUÉ: ¿Por qué crear trampas?
Los atacantes seguirán escaneando /admin. Por tanto, podemos convertir esta ruta en un Honeypot falso, de modo que cualquier IP que intente acceder al mismo será considerada maliciosa y bloqueada instantáneamente.
CÓMO: Fake Admin + Fail2Ban
Este método es algo complejo pero muy efectivo.
- Crear vista de Admin falsa: Oculta la verdadera URL del administrador como se indica en el punto 1 y conecta una vista falsa a la ruta
/admin/.
# urls.py
from django.urls import path
from . import views # importando la vista falsa
urlpatterns = [
path('my-secret-admin-portal-b7x9z/', admin.site.urls), # verdadera
path('admin/', views.admin_honeypot), # falsa (trampa)
]
# views.py
import logging
from django.http import HttpResponseForbidden
# Configura un logger específico para honeypot (se debe definir 'honeypot' en settings.py)
honeypot_logger = logging.getLogger('honeypot')
def admin_honeypot(request):
# Registra la IP del intento de acceso
ip = request.META.get('REMOTE_ADDR')
honeypot_logger.warning(f"HONEYPOT: Intento de acceso al admin desde {ip}")
# Muestra un error 403 a los atacantes
return HttpResponseForbidden()
-
Configurar Fail2Ban:
Fail2Banes una herramienta que monitorea archivos de registro del servidor en tiempo real y, al detectar un patrón específico (por ejemplo, "HONEYPOT: ..."), agrega la IP que generó ese registro aiptables(firewall de Linux) y la bloquea.-
Configura Django para que registre en un archivo
honeypot.log. -
Configura Fail2Ban para que monitoree
honeypot.log. -
Cuando alguien accede a
/admin/,views.pyregistra el intento y Fail2Ban detecta esto y bloquea inmediatamente todo acceso desde esa IP (SSH, HTTP, etc.).
-
Resumen
La seguridad de la página de administración de Django radica en establecer múltiples capas de defensa.
-
(Obligatorio) 1. Cambio de URL: Invierta 5 minutos ahora para hacerlo.
-
(Recomendado) 2. Restricción de IP: Es la opción más fuerte si hay IPs fijas.
-
(Recomendado) 3. django-axes: Evita ataques de fuerza bruta.
-
(Altamente recomendado) 4. 2FA: Previene la apropiación de cuentas de administrador.
-
(Avanzado) 5. Honeypot: Protegerá todo el servidor de manera agresiva.
Dejar /admin tal como está es negligencia en seguridad. Revise su urls.py ahora mismo.
No hay comentarios.