GuardianUnivalle-Benito-Yucra 0.1.48__py3-none-any.whl → 0.1.50__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of GuardianUnivalle-Benito-Yucra might be problematic. Click here for more details.
- GuardianUnivalle_Benito_Yucra/auditoria/auditoria_servidor.py +119 -0
- GuardianUnivalle_Benito_Yucra/auditoria/registro_auditoria.py +8 -123
- {guardianunivalle_benito_yucra-0.1.48.dist-info → guardianunivalle_benito_yucra-0.1.50.dist-info}/METADATA +1 -1
- {guardianunivalle_benito_yucra-0.1.48.dist-info → guardianunivalle_benito_yucra-0.1.50.dist-info}/RECORD +7 -6
- {guardianunivalle_benito_yucra-0.1.48.dist-info → guardianunivalle_benito_yucra-0.1.50.dist-info}/WHEEL +0 -0
- {guardianunivalle_benito_yucra-0.1.48.dist-info → guardianunivalle_benito_yucra-0.1.50.dist-info}/licenses/LICENSE +0 -0
- {guardianunivalle_benito_yucra-0.1.48.dist-info → guardianunivalle_benito_yucra-0.1.50.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import json
|
|
3
|
+
import platform
|
|
4
|
+
import socket
|
|
5
|
+
import uuid
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
from django.utils.deprecation import MiddlewareMixin
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger("auditoria_servidor")
|
|
10
|
+
logger.setLevel(logging.INFO)
|
|
11
|
+
if not logger.handlers:
|
|
12
|
+
handler = logging.StreamHandler()
|
|
13
|
+
handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s"))
|
|
14
|
+
logger.addHandler(handler)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def obtener_datos_maquina(request):
|
|
18
|
+
"""
|
|
19
|
+
Retorna un diccionario con información del cliente y del servidor.
|
|
20
|
+
No accede a ningún modelo Django.
|
|
21
|
+
"""
|
|
22
|
+
datos = {}
|
|
23
|
+
try:
|
|
24
|
+
# Datos del cliente
|
|
25
|
+
datos["ip"] = request.META.get("HTTP_X_FORWARDED_FOR", "").split(",")[0] or request.META.get("REMOTE_ADDR", "")
|
|
26
|
+
datos["user_agent"] = request.META.get("HTTP_USER_AGENT", "")
|
|
27
|
+
datos["navegador"] = datos["user_agent"].split("/")[0] if "/" in datos["user_agent"] else datos["user_agent"]
|
|
28
|
+
datos["sistema_operativo"] = platform.system()
|
|
29
|
+
datos["url"] = request.build_absolute_uri()
|
|
30
|
+
datos["fecha"] = datetime.now().isoformat()
|
|
31
|
+
|
|
32
|
+
# Datos del servidor
|
|
33
|
+
datos["servidor_nombre"] = socket.gethostname()
|
|
34
|
+
datos["servidor_ip"] = socket.gethostbyname(socket.gethostname())
|
|
35
|
+
datos["servidor_uuid"] = str(uuid.uuid4())
|
|
36
|
+
except Exception as e:
|
|
37
|
+
logger.error(f"Error obteniendo datos de máquina: {e}")
|
|
38
|
+
return datos
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def analizar_comportamiento_cliente(datos):
|
|
42
|
+
"""
|
|
43
|
+
Analiza los datos del cliente y retorna una evaluación general:
|
|
44
|
+
(nivel_severidad, descripcion)
|
|
45
|
+
"""
|
|
46
|
+
if not datos:
|
|
47
|
+
return "BAJA", "Sin datos del cliente"
|
|
48
|
+
|
|
49
|
+
ip = datos.get("ip", "")
|
|
50
|
+
navegador = datos.get("navegador", "")
|
|
51
|
+
descripcion = f"Actividad detectada desde IP {ip} con navegador {navegador}"
|
|
52
|
+
|
|
53
|
+
if "bot" in navegador.lower():
|
|
54
|
+
return "MEDIA", descripcion + " (posible bot)"
|
|
55
|
+
return "BAJA", descripcion
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def registrar_evento(tipo, descripcion, severidad="BAJA", usuario_id=None, extra=None):
|
|
59
|
+
"""
|
|
60
|
+
Prepara un registro de auditoría (para luego guardarlo en BD desde Django).
|
|
61
|
+
"""
|
|
62
|
+
try:
|
|
63
|
+
registro = {
|
|
64
|
+
"tipo": tipo,
|
|
65
|
+
"descripcion": descripcion,
|
|
66
|
+
"severidad": severidad,
|
|
67
|
+
"usuario_id": usuario_id, # <-- guardamos ID en lugar de FK
|
|
68
|
+
"fecha": datetime.now().isoformat(),
|
|
69
|
+
"extra": extra or {},
|
|
70
|
+
}
|
|
71
|
+
logger.info("[AUDITORIA] %s", json.dumps(registro, ensure_ascii=False))
|
|
72
|
+
return registro
|
|
73
|
+
except Exception as e:
|
|
74
|
+
logger.error(f"Error registrando evento: {e}")
|
|
75
|
+
return None
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class AuditoriaServidorMiddleware(MiddlewareMixin):
|
|
79
|
+
"""
|
|
80
|
+
Middleware que integra toda la información generada por los detectores (SQLi, XSS, etc.)
|
|
81
|
+
y la deja lista en request.guardian_auditoria para que el backend (Django)
|
|
82
|
+
la guarde en la base de datos.
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
def process_request(self, request):
|
|
86
|
+
try:
|
|
87
|
+
datos_cliente = obtener_datos_maquina(request)
|
|
88
|
+
severidad, descripcion = analizar_comportamiento_cliente(datos_cliente)
|
|
89
|
+
|
|
90
|
+
# Base del registro
|
|
91
|
+
registro_base = {
|
|
92
|
+
"datos_cliente": datos_cliente,
|
|
93
|
+
"descripcion": descripcion,
|
|
94
|
+
"severidad": severidad,
|
|
95
|
+
"eventos_detectados": [],
|
|
96
|
+
"usuario_id": getattr(request.user, "id", None) # <-- si está autenticado
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
# Integrar información de ataques detectada por otros middlewares
|
|
100
|
+
for attr in ["sql_attack_info", "xss_attack_info", "csrf_attack_info", "dos_attack_info"]:
|
|
101
|
+
if hasattr(request, attr):
|
|
102
|
+
registro_base["eventos_detectados"].append(getattr(request, attr))
|
|
103
|
+
|
|
104
|
+
# Si hubo algún evento sospechoso
|
|
105
|
+
if registro_base["eventos_detectados"]:
|
|
106
|
+
registrar_evento(
|
|
107
|
+
tipo="ATAQUE_DETECTADO",
|
|
108
|
+
descripcion="Se detectó comportamiento sospechoso en la solicitud",
|
|
109
|
+
severidad="ALTA",
|
|
110
|
+
usuario_id=registro_base["usuario_id"],
|
|
111
|
+
extra=registro_base,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
# Guardar la info para el backend (sin registrar aún en BD)
|
|
115
|
+
request.guardian_auditoria = registro_base
|
|
116
|
+
|
|
117
|
+
except Exception as e:
|
|
118
|
+
logger.error(f"Error en AuditoriaServidorMiddleware: {e}")
|
|
119
|
+
return None
|
|
@@ -1,152 +1,37 @@
|
|
|
1
|
-
# E:\EcuacionPotosi\GuardianUnivalle-Benito-Yucra\GuardianUnivalle_Benito_Yucra\auditoria\registro_auditoria.py
|
|
2
|
-
|
|
3
1
|
import os
|
|
4
2
|
import datetime
|
|
5
3
|
import json
|
|
6
|
-
import platform
|
|
7
|
-
import requests
|
|
8
|
-
from django.utils.timezone import now
|
|
9
|
-
from user_agents import parse
|
|
10
4
|
|
|
11
5
|
LOG_FILE = "auditoria_guardian.log"
|
|
12
6
|
|
|
13
|
-
# =====================================================
|
|
14
|
-
# === FUNCIONES DE CAPTURA Y ANÁLISIS DE CLIENTE ===
|
|
15
|
-
# =====================================================
|
|
16
7
|
|
|
17
|
-
def
|
|
18
|
-
|
|
8
|
+
def registrar_evento(
|
|
9
|
+
tipo: str,
|
|
10
|
+
descripcion: str = "",
|
|
11
|
+
severidad: str = "MEDIA",
|
|
12
|
+
extra: dict | None = None,
|
|
13
|
+
):
|
|
19
14
|
try:
|
|
20
|
-
# --- IP real ---
|
|
21
|
-
ip = (
|
|
22
|
-
request.META.get("HTTP_X_FORWARDED_FOR")
|
|
23
|
-
or request.META.get("REMOTE_ADDR")
|
|
24
|
-
or "0.0.0.0"
|
|
25
|
-
)
|
|
26
|
-
ip = ip.split(",")[0].strip()
|
|
27
|
-
|
|
28
|
-
# --- User Agent ---
|
|
29
|
-
user_agent_str = request.META.get("HTTP_USER_AGENT", "Desconocido")
|
|
30
|
-
user_agent = parse(user_agent_str)
|
|
31
|
-
navegador = f"{user_agent.browser.family} {user_agent.browser.version_string}"
|
|
32
|
-
sistema = f"{user_agent.os.family} {user_agent.os.version_string}"
|
|
33
|
-
|
|
34
|
-
# --- Geolocalización (ipinfo.io gratuita) ---
|
|
35
|
-
geo_data = {}
|
|
36
|
-
try:
|
|
37
|
-
r = requests.get(f"https://ipinfo.io/{ip}/json", timeout=2)
|
|
38
|
-
if r.status_code == 200:
|
|
39
|
-
geo_data = r.json()
|
|
40
|
-
except Exception:
|
|
41
|
-
pass
|
|
42
|
-
|
|
43
|
-
pais = geo_data.get("country", "Desconocido")
|
|
44
|
-
ciudad = geo_data.get("city", "Desconocida")
|
|
45
|
-
isp = geo_data.get("org", "Desconocido")
|
|
46
|
-
|
|
47
|
-
# --- Usuario autenticado ---
|
|
48
|
-
usuario = "Anónimo"
|
|
49
|
-
if hasattr(request, "user") and request.user.is_authenticated:
|
|
50
|
-
usuario = getattr(request.user, "username", "Desconocido")
|
|
51
|
-
|
|
52
|
-
# --- Construir estructura ---
|
|
53
|
-
datos = {
|
|
54
|
-
"fecha": now().strftime("%Y-%m-%d %H:%M:%S"),
|
|
55
|
-
"ip": ip,
|
|
56
|
-
"pais": pais,
|
|
57
|
-
"ciudad": ciudad,
|
|
58
|
-
"isp": isp,
|
|
59
|
-
"usuario": usuario,
|
|
60
|
-
"user_agent": user_agent_str,
|
|
61
|
-
"navegador": navegador,
|
|
62
|
-
"sistema_operativo": sistema,
|
|
63
|
-
"url": request.path,
|
|
64
|
-
"metodo": request.method,
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return datos
|
|
68
|
-
except Exception as e:
|
|
69
|
-
return {"error": str(e)}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
def analizar_comportamiento_cliente(datos_cliente: dict) -> tuple[str, str]:
|
|
73
|
-
"""
|
|
74
|
-
Aplica reglas básicas de detección:
|
|
75
|
-
- IP sospechosa o repetitiva
|
|
76
|
-
- Agente extraño o vacío
|
|
77
|
-
- Peticiones sospechosas (ej: /admin, /etc/passwd)
|
|
78
|
-
Devuelve: (nivel_riesgo, descripcion)
|
|
79
|
-
"""
|
|
80
|
-
descripcion = []
|
|
81
|
-
riesgo = "BAJO"
|
|
82
|
-
|
|
83
|
-
ip = datos_cliente.get("ip", "")
|
|
84
|
-
user_agent = datos_cliente.get("user_agent", "").lower()
|
|
85
|
-
ruta = datos_cliente.get("url", "")
|
|
86
|
-
|
|
87
|
-
# === Reglas simples ===
|
|
88
|
-
if not user_agent or "curl" in user_agent or "python" in user_agent:
|
|
89
|
-
descripcion.append("Agente de usuario anómalo (posible bot o script).")
|
|
90
|
-
riesgo = "MEDIO"
|
|
91
|
-
|
|
92
|
-
if "admin" in ruta or "etc/passwd" in ruta or "../" in ruta:
|
|
93
|
-
descripcion.append("Ruta sospechosa accedida.")
|
|
94
|
-
riesgo = "ALTO"
|
|
95
|
-
|
|
96
|
-
if "Desconocida" in ip or ip.startswith("192.168.") is False:
|
|
97
|
-
descripcion.append(f"IP externa detectada: {ip}")
|
|
98
|
-
riesgo = "MEDIO"
|
|
99
|
-
|
|
100
|
-
if not datos_cliente.get("url"):
|
|
101
|
-
descripcion.append("Petición sin parámetros ni cabeceras útiles.")
|
|
102
|
-
riesgo = "BAJO"
|
|
103
|
-
|
|
104
|
-
if not descripcion:
|
|
105
|
-
descripcion.append("Acceso normal detectado.")
|
|
106
|
-
|
|
107
|
-
return riesgo, " | ".join(descripcion)
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
# =====================================================
|
|
111
|
-
# === FUNCIÓN PRINCIPAL DE REGISTRO ===
|
|
112
|
-
# =====================================================
|
|
113
|
-
def registrar_evento(request, tipo: str = "ACCESO", extra: dict | None = None):
|
|
114
|
-
"""
|
|
115
|
-
Registra un evento de auditoría detallado del cliente.
|
|
116
|
-
Incluye login exitoso, acceso normal y detección de ataques.
|
|
117
|
-
"""
|
|
118
|
-
try:
|
|
119
|
-
datos_cliente = obtener_datos_maquina(request)
|
|
120
|
-
severidad, descripcion = analizar_comportamiento_cliente(datos_cliente)
|
|
121
|
-
|
|
122
15
|
evento = {
|
|
123
16
|
"fecha": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
|
124
17
|
"tipo": tipo,
|
|
125
18
|
"descripcion": descripcion,
|
|
126
19
|
"severidad": severidad,
|
|
127
|
-
"cliente": datos_cliente,
|
|
128
20
|
"extra": extra or {},
|
|
129
21
|
}
|
|
130
22
|
|
|
131
|
-
# Crear carpeta solo si hay directorio en la ruta
|
|
23
|
+
# ✅ Crear carpeta solo si hay directorio en la ruta
|
|
132
24
|
log_dir = os.path.dirname(LOG_FILE)
|
|
133
25
|
if log_dir:
|
|
134
26
|
os.makedirs(log_dir, exist_ok=True)
|
|
135
27
|
|
|
136
|
-
# Registrar en archivo
|
|
137
28
|
with open(LOG_FILE, "a", encoding="utf-8") as f:
|
|
138
29
|
f.write(json.dumps(evento, ensure_ascii=False) + "\n")
|
|
139
30
|
|
|
140
|
-
# Log en consola para depuración local
|
|
141
|
-
print(f"[AUDITORÍA] Evento registrado: {evento['descripcion']} (nivel {severidad})")
|
|
142
|
-
|
|
143
31
|
except Exception as e:
|
|
144
|
-
print(f"[
|
|
32
|
+
print(f"[Auditoría] Error al registrar evento: {e}")
|
|
145
33
|
|
|
146
34
|
|
|
147
|
-
# =====================================================
|
|
148
|
-
# === CONSULTA DE REGISTROS (opcional) ===
|
|
149
|
-
# =====================================================
|
|
150
35
|
def generar_reporte() -> str:
|
|
151
36
|
"""Devuelve todo el contenido del archivo de auditoría."""
|
|
152
37
|
if not os.path.exists(LOG_FILE):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: GuardianUnivalle-Benito-Yucra
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.50
|
|
4
4
|
Summary: Middleware y detectores de seguridad (SQLi, XSS, CSRF, DoS, Keylogger) para Django/Flask
|
|
5
5
|
Author-email: Andres Benito Calle Yucra <benitoandrescalle035@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
GuardianUnivalle_Benito_Yucra/__init__.py,sha256=lbIRb8fCFYfAdyJV6NsYVZJ5pKYSJZKhhK-En9g_1M8,762
|
|
2
2
|
GuardianUnivalle_Benito_Yucra/utilidades.py,sha256=lFNVnlyTSYmQ1CqtmHx6aefK5uNw0wsMdHRQyxAIZy0,120
|
|
3
|
-
GuardianUnivalle_Benito_Yucra/auditoria/
|
|
3
|
+
GuardianUnivalle_Benito_Yucra/auditoria/auditoria_servidor.py,sha256=ZXyzegZb_iQI4ICzPBw2uJeco4LMYZ1wv12DuTnKb7M,4543
|
|
4
|
+
GuardianUnivalle_Benito_Yucra/auditoria/registro_auditoria.py,sha256=NnKBOeRWkXVGaMBeQRYU528rWlaBDBPmTAzfji9n8fw,1135
|
|
4
5
|
GuardianUnivalle_Benito_Yucra/criptografia/cifrado_aead.py,sha256=wfoRpaKvOqPbollNQsDNUNWClYJlXYTKTYvv0qcR6aI,962
|
|
5
6
|
GuardianUnivalle_Benito_Yucra/criptografia/intercambio_claves.py,sha256=9djnlzb022hUhrDbQyWz7lWLbkn_vQZ4K7qar1FXYmo,829
|
|
6
7
|
GuardianUnivalle_Benito_Yucra/criptografia/kdf.py,sha256=_sbepEY1qHEKga0ExrX2WRg1HeCPY5MC5CfXZWYyl-A,709
|
|
@@ -13,8 +14,8 @@ GuardianUnivalle_Benito_Yucra/middleware_web/middleware_web.py,sha256=23pLLYqliU
|
|
|
13
14
|
GuardianUnivalle_Benito_Yucra/mitigacion/limitador_peticion.py,sha256=ipMOebYhql-6mSyHs0ddYXOcXq9w8P_IXLlpiIqGncw,246
|
|
14
15
|
GuardianUnivalle_Benito_Yucra/mitigacion/lista_bloqueo.py,sha256=6AYWII4mrmwCLHCvGTyoBxR4Oasr4raSHpFbVjqn7d8,193
|
|
15
16
|
GuardianUnivalle_Benito_Yucra/puntuacion/puntuacion_amenaza.py,sha256=Wx5XfcII4oweLvZsTBEJ7kUc9pMpP5-36RfI5C5KJXo,561
|
|
16
|
-
guardianunivalle_benito_yucra-0.1.
|
|
17
|
-
guardianunivalle_benito_yucra-0.1.
|
|
18
|
-
guardianunivalle_benito_yucra-0.1.
|
|
19
|
-
guardianunivalle_benito_yucra-0.1.
|
|
20
|
-
guardianunivalle_benito_yucra-0.1.
|
|
17
|
+
guardianunivalle_benito_yucra-0.1.50.dist-info/licenses/LICENSE,sha256=5e4IdL542v1E8Ft0A24GZjrxZeTsVK7XrS3mZEUhPtM,37
|
|
18
|
+
guardianunivalle_benito_yucra-0.1.50.dist-info/METADATA,sha256=S1Slmtk8V-fzvKQqKOc-GvCcQ46C3DrDCPTlNQkATLw,1893
|
|
19
|
+
guardianunivalle_benito_yucra-0.1.50.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
20
|
+
guardianunivalle_benito_yucra-0.1.50.dist-info/top_level.txt,sha256=HTWfZM64WAV_QYr5cnXnLuabQt92dvlxqlR3pCwpbDQ,30
|
|
21
|
+
guardianunivalle_benito_yucra-0.1.50.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|