GuardianUnivalle-Benito-Yucra 0.1.50__py3-none-any.whl → 0.1.51__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.

@@ -3,14 +3,16 @@ import time
3
3
  import logging
4
4
  import json
5
5
  from collections import deque
6
- from typing import Dict, List
6
+ from typing import Dict, List, Set
7
7
  from django.conf import settings
8
8
  from django.utils.deprecation import MiddlewareMixin
9
- from ..mitigacion.limitador_peticion import limitar_peticion
10
- from ..auditoria.registro_auditoria import registrar_evento
9
+ from django.http import HttpResponseForbidden
10
+ import requests # ⬅️ Necesario para la función de scraping
11
+ import re # ⬅️ Necesario para el parseo de IPs/CIDR
12
+ from ipaddress import ip_address, IPv4Address, IPv4Network # Necesario para el Escaneo Avanzado (CIDR)
11
13
 
12
14
  # =====================================================
13
- # === CONFIGURACIÓN DEL LOGGER ===
15
+ # === CONFIGURACIÓN GLOBAL Y LOGGER ===
14
16
  # =====================================================
15
17
  logger = logging.getLogger("dosdefense")
16
18
  logger.setLevel(logging.INFO)
@@ -20,21 +22,112 @@ if not logger.handlers:
20
22
  logger.addHandler(handler)
21
23
 
22
24
  # =====================================================
23
- # === PARÁMETROS DE CONFIGURACIÓN BASE ===
25
+ # === CONFIGURACIÓN DE INTELIGENCIA DE AMENAZAS (THREAT INTEL) ===
24
26
  # =====================================================
25
- LIMITE_PETICIONES = getattr(settings, "DOS_LIMITE_PETICIONES", 100) # por minuto
27
+ # URLs CONCEPTUALES de donde EXTRAERÍAS IPs/CIDR
28
+ IP_BLACKLIST_SOURCES = [
29
+ "http://api.sitio_de_inteligencia.com/blacklist/ip_list",
30
+ "http://otro_sitio.com/export_ips.txt",
31
+ "https://iplists.firehol.org/files/firehol_level1.netset",
32
+ ]
33
+
34
+ # Cabeceras para simular un navegador
35
+ SCRAPING_HEADERS = {
36
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
37
+ }
38
+
39
+ # =====================================================
40
+ # === FUNCIONES DE INTELIGENCIA DE AMENAZAS ===
41
+ # =====================================================
42
+
43
+ def fetch_and_parse_blacklists() -> Set[str]:
44
+ """
45
+ Intenta obtener y parsear IPs/CIDR de varias fuentes externas.
46
+ """
47
+ global_blacklist: Set[str] = set()
48
+ # Patrón Regex para IPs (admite también rangos CIDR)
49
+ ip_pattern = re.compile(r'\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(/\d{1,2})?\b')
50
+
51
+ for url in IP_BLACKLIST_SOURCES:
52
+ try:
53
+ response = requests.get(url, headers=SCRAPING_HEADERS, timeout=15)
54
+ response.raise_for_status()
55
+
56
+ found_ips = set(ip_pattern.findall(response.text))
57
+
58
+ # Limpieza
59
+ cleaned_ips = {ip[0] for ip in found_ips if ip[0] not in ('0.0.0.0', '255.255.255.255')}
60
+
61
+ global_blacklist.update(cleaned_ips)
62
+ logger.info(f"[Threat Intel] Éxito al obtener {len(cleaned_ips)} IPs/CIDR de {url}")
63
+
64
+ except requests.exceptions.RequestException as e:
65
+ logger.error(f"[Threat Intel] Error de conexión con {url}: {e}")
66
+ except Exception as e:
67
+ logger.error(f"[Threat Intel] Error inesperado al parsear {url}: {e}")
68
+
69
+ if '127.0.0.1' in global_blacklist:
70
+ global_blacklist.remove('127.0.0.1')
71
+
72
+ return global_blacklist
73
+
74
+ def check_ip_in_advanced_blacklist(client_ip: str, global_blacklist_cidrs: Set[str]) -> bool:
75
+ """
76
+ Escaneo avanzado: Chequea si una IP está en la lista negra, incluyendo rangos CIDR.
77
+ """
78
+ if not global_blacklist_cidrs:
79
+ return False
80
+
81
+ try:
82
+ ip_a_chequear = IPv4Address(client_ip)
83
+
84
+ # 1. Chequeo rápido de IPs individuales
85
+ if client_ip in global_blacklist_cidrs:
86
+ return True
87
+
88
+ # 2. Chequeo de rangos CIDR (más lento)
89
+ for cidr_entry in global_blacklist_cidrs:
90
+ if '/' in cidr_entry:
91
+ try:
92
+ if ip_a_chequear in IPv4Network(cidr_entry, strict=False):
93
+ return True
94
+ except ValueError:
95
+ continue # No es una red CIDR válida, continuar
96
+ return False
97
+
98
+ except ValueError:
99
+ logger.error(f"IP del cliente inválida o no IPv4: {client_ip}")
100
+ return False
101
+
102
+ # =====================================================
103
+ # === PARÁMETROS DE CONFIGURACIÓN BASE Y SCORE ===
104
+ # =====================================================
105
+ LIMITE_PETICIONES = getattr(settings, "DOS_LIMITE_PETICIONES", 100)
26
106
  VENTANA_SEGUNDOS = getattr(settings, "DOS_VENTANA_SEGUNDOS", 60)
27
107
  PESO_DOS = getattr(settings, "DOS_PESO", 0.6)
28
108
  LIMITE_ENDPOINTS_DISTINTOS = getattr(settings, "DOS_LIMITE_ENDPOINTS", 50)
29
109
  TRUSTED_IPS = getattr(settings, "DOS_TRUSTED_IPS", [])
110
+ TIEMPO_BLOQUEO_SEGUNDOS = getattr(settings, "DOS_TIEMPO_BLOQUEO", 300)
111
+
112
+ # Parámetros del Score Avanzado
113
+ PESO_BLACKLIST = getattr(settings, "DOS_PESO_BLACKLIST", 0.3)
114
+ PESO_HEURISTICA = getattr(settings, "DOS_PESO_HEURISTICA", 0.1)
115
+ UMBRAL_BLOQUEO = getattr(settings, "DOS_UMBRAL_BLOQUEO", 0.8)
116
+
117
+ # === CARGA INICIAL DE LA LISTA NEGRA ===
118
+ try:
119
+ IP_BLACKLIST: Set[str] = fetch_and_parse_blacklists()
120
+ logger.info(f"Lista Negra Externa cargada con {len(IP_BLACKLIST)} IPs/CIDR.")
121
+ except Exception as e:
122
+ logger.error(f"Error al cargar la IP Blacklist: {e}. Usando lista vacía.")
123
+ IP_BLACKLIST = set()
30
124
 
31
125
  # =====================================================
32
126
  # === REGISTRO TEMPORAL EN MEMORIA ===
33
127
  # =====================================================
34
- # Estructura: { ip: deque([timestamps]), ... }
35
- # deque es eficiente para ventanas deslizantes
36
128
  REGISTRO_SOLICITUDES: Dict[str, deque] = {}
37
129
  REGISTRO_ENDPOINTS: Dict[str, set] = {}
130
+ BLOQUEOS_TEMPORALES: Dict[str, float] = {}
38
131
 
39
132
  # =====================================================
40
133
  # === FUNCIONES AUXILIARES ===
@@ -46,22 +139,29 @@ def get_client_ip(request) -> str:
46
139
  return x_forwarded_for.split(",")[0].strip()
47
140
  return request.META.get("REMOTE_ADDR", "") or "0.0.0.0"
48
141
 
49
-
50
142
  def limpiar_registro_global():
51
- """Elimina IPs sin actividad reciente para evitar uso excesivo de memoria."""
143
+ """Elimina IPs sin actividad reciente y desbloquea IPs temporales."""
144
+ # ... (La implementación de limpiar_registro_global permanece igual)
52
145
  ahora = time.time()
53
- expiracion = VENTANA_SEGUNDOS * 2 # doble ventana
54
- inactivas = [
55
- ip for ip, tiempos in REGISTRO_SOLICITUDES.items()
56
- if tiempos and ahora - tiempos[-1] > expiracion
57
- ]
146
+ expiracion = VENTANA_SEGUNDOS * 2
147
+ inactivas = []
148
+
149
+ for ip, tiempos in REGISTRO_SOLICITUDES.items():
150
+ if tiempos and ahora - tiempos[-1] > expiracion:
151
+ inactivas.append(ip)
152
+
58
153
  for ip in inactivas:
59
154
  REGISTRO_SOLICITUDES.pop(ip, None)
60
155
  REGISTRO_ENDPOINTS.pop(ip, None)
61
-
156
+
157
+ ips_a_desbloquear = [ip for ip, tiempo_desbloqueo in BLOQUEOS_TEMPORALES.items() if ahora > tiempo_desbloqueo]
158
+ for ip in ips_a_desbloquear:
159
+ BLOQUEOS_TEMPORALES.pop(ip, None)
160
+ logger.info(f"[Desbloqueo] IP {ip} desbloqueada automáticamente.")
62
161
 
63
162
  def limpiar_registro(ip: str):
64
163
  """Limpia peticiones antiguas fuera de la ventana de tiempo."""
164
+ # ... (La implementación de limpiar_registro permanece igual)
65
165
  ahora = time.time()
66
166
  if ip not in REGISTRO_SOLICITUDES:
67
167
  REGISTRO_SOLICITUDES[ip] = deque()
@@ -69,29 +169,48 @@ def limpiar_registro(ip: str):
69
169
  while tiempos and ahora - tiempos[0] > VENTANA_SEGUNDOS:
70
170
  tiempos.popleft()
71
171
 
72
-
73
172
  def calcular_nivel_amenaza_dos(tasa_peticion: int, limite: int = LIMITE_PETICIONES) -> float:
74
- """
75
- Calcula la puntuación de amenaza DoS.
76
- Fórmula: S_dos = w_dos * (tasa_peticion / limite)
77
- """
173
+ """Calcula la puntuación de amenaza DoS (Rate Limiting)."""
174
+ # ... (La implementación de calcular_nivel_amenaza_dos permanece igual)
78
175
  proporcion = tasa_peticion / max(limite, 1)
79
176
  s_dos = PESO_DOS * min(proporcion, 2.0)
80
177
  return round(min(s_dos, 1.0), 3)
81
178
 
82
179
 
180
+ # =====================================================
181
+ # === FUNCIONES INTERNAS DE SEGURIDAD Y AUDITORÍA ===
182
+ # =====================================================
183
+ def limitar_peticion(usuario_id: str):
184
+ """Implementa la mitigación: Bloquea temporalmente la IP."""
185
+ ahora = time.time()
186
+ tiempo_desbloqueo = ahora + TIEMPO_BLOQUEO_SEGUNDOS
187
+ BLOQUEOS_TEMPORALES[usuario_id] = tiempo_desbloqueo
188
+ logger.warning(
189
+ f"[Bloqueo Activo] IP {usuario_id} bloqueada temporalmente hasta {time.ctime(tiempo_desbloqueo)}"
190
+ )
191
+
192
+ def registrar_evento(tipo: str, descripcion: str, severidad: str = "MEDIA"):
193
+ """Simula el registro de auditoría de un evento de seguridad."""
194
+ evento = {
195
+ "tipo": tipo,
196
+ "descripcion": descripcion,
197
+ "severidad": severidad,
198
+ "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
199
+ }
200
+ logger.info(f"[AUDITORÍA] {json.dumps(evento, ensure_ascii=False)}")
201
+
83
202
  def detectar_dos(ip: str, tasa_peticion: int, limite: int = LIMITE_PETICIONES) -> bool:
84
- """Evalúa si la tasa de peticiones excede el umbral permitido."""
203
+ """Evalúa si la tasa de peticiones excede el umbral permitido y aplica mitigación."""
204
+ # ... (La implementación de detectar_dos permanece igual)
85
205
  if tasa_peticion > limite:
86
206
  registrar_evento(
87
207
  tipo="DoS",
88
208
  descripcion=f"Alta tasa de peticiones desde {ip}: {tasa_peticion} req/min (límite {limite})",
89
209
  severidad="ALTA",
90
210
  )
91
- limitar_peticion(usuario_id="anonimo")
211
+ limitar_peticion(usuario_id=ip)
92
212
  return True
93
213
  elif tasa_peticion > limite * 0.75:
94
- # Umbral de advertencia
95
214
  registrar_evento(
96
215
  tipo="DoS",
97
216
  descripcion=f"Posible saturación desde {ip}: {tasa_peticion} req/min",
@@ -99,16 +218,21 @@ def detectar_dos(ip: str, tasa_peticion: int, limite: int = LIMITE_PETICIONES) -
99
218
  )
100
219
  return False
101
220
 
102
-
103
- def analizar_headers(user_agent: str, referer: str) -> List[str]:
104
- """Detecta patrones de agentes o cabeceras sospechosas."""
221
+ def analizar_headers_avanzado(user_agent: str, referer: str) -> List[str]:
222
+ """Detecta patrones sospechosos, penalizando User-Agents automatizados."""
223
+ # ... (La implementación de analizar_headers_avanzado permanece igual)
105
224
  sospechas = []
106
- if not user_agent or len(user_agent) < 10:
107
- sospechas.append("User-Agent vacío o anómalo")
108
- if "curl" in user_agent.lower() or "python" in user_agent.lower():
109
- sospechas.append("User-Agent indica script o bot")
110
- if referer and any(palabra in referer.lower() for palabra in ["attack", "scan", "bot"]):
111
- sospechas.append("Referer sospechoso")
225
+
226
+ if not user_agent or len(user_agent) < 10 or user_agent.lower() == "python-requests/2.25.1":
227
+ sospechas.append("User-Agent vacío/Defecto")
228
+
229
+ automation_keywords = ["curl", "python", "wget", "bot", "spider", "scraper", "headless", "phantom"]
230
+ if any(patron in user_agent.lower() for patron in automation_keywords):
231
+ sospechas.append("Herramienta de automatización detectada")
232
+
233
+ if referer and any(palabra in referer.lower() for palabra in ["attack", "scan"]):
234
+ sospechas.append("Referer indicando abuso")
235
+
112
236
  return sospechas
113
237
 
114
238
 
@@ -117,110 +241,95 @@ def analizar_headers(user_agent: str, referer: str) -> List[str]:
117
241
  # =====================================================
118
242
  class DOSDefenseMiddleware(MiddlewareMixin):
119
243
  """
120
- Middleware de detección y registro de ataques DoS.
244
+ Middleware de detección, registro y mitigación de ataques DoS/Scraping avanzado.
121
245
  """
122
246
 
123
247
  def process_request(self, request):
124
248
  limpiar_registro_global()
125
249
 
126
250
  client_ip = get_client_ip(request)
251
+
252
+ # 1. BLOQUEOS Y EXCEPCIONES PREVIAS
127
253
  if client_ip in TRUSTED_IPS:
128
254
  return None
255
+
256
+ # BLOQUEO TEMPORAL: IPs previamente bloqueadas por alto Score o DoS
257
+ if client_ip in BLOQUEOS_TEMPORALES and time.time() < BLOQUEOS_TEMPORALES[client_ip]:
258
+ registrar_evento(
259
+ tipo="Temporary Block",
260
+ descripcion=f"Bloqueo temporal por abuso previo: IP {client_ip}.",
261
+ severidad="ALTA",
262
+ )
263
+ return HttpResponseForbidden("Acceso denegado temporalmente por comportamiento sospechoso.")
129
264
 
265
+ # 2. ANÁLISIS DE LA PETICIÓN Y CÁLCULO DE MÉTRICAS BASE
130
266
  user_agent = request.META.get("HTTP_USER_AGENT", "Desconocido")
131
267
  referer = request.META.get("HTTP_REFERER", "")
132
268
  path = request.path
133
269
 
134
- # Registrar endpoint accedido
270
+ # Mantener ventana deslizante y tasa
135
271
  REGISTRO_ENDPOINTS.setdefault(client_ip, set()).add(path)
136
-
137
- # Mantener ventana deslizante
138
272
  limpiar_registro(client_ip)
139
273
  REGISTRO_SOLICITUDES[client_ip].append(time.time())
140
274
 
141
275
  tasa = len(REGISTRO_SOLICITUDES[client_ip])
142
- nivel = calcular_nivel_amenaza_dos(tasa)
143
- es_dos = detectar_dos(client_ip, tasa)
144
-
145
- descripcion = []
146
- sospechas_headers = analizar_headers(user_agent, referer)
147
- if sospechas_headers:
148
- descripcion.extend(sospechas_headers)
149
-
150
- # Verificar exceso de endpoints distintos (indicativo de escaneo)
151
- if len(REGISTRO_ENDPOINTS[client_ip]) > LIMITE_ENDPOINTS_DISTINTOS:
152
- descripcion.append("Número anormal de endpoints distintos accedidos")
153
-
154
- if es_dos or descripcion:
155
- descripcion.insert(0, f"Tasa actual: {tasa} req/min (nivel {nivel:.2f})")
276
+
277
+ # 3. CÁLCULO DE LOS COMPONENTES DEL SCORE DE AMENAZA
278
+
279
+ # S_dos: Tasa de Petición (Rate Limiting)
280
+ nivel_dos = calcular_nivel_amenaza_dos(tasa)
281
+
282
+ # S_blacklist: Escaneo Avanzado (CIDR)
283
+ nivel_blacklist = PESO_BLACKLIST if check_ip_in_advanced_blacklist(client_ip, IP_BLACKLIST) else 0
284
+
285
+ # S_heuristica: Análisis de Comportamiento (Scraping/Escaneo)
286
+ sospechas_headers = analizar_headers_avanzado(user_agent, referer)
287
+
288
+ score_headers = 0.5 if sospechas_headers else 0
289
+ score_endpoints = 0.5 if len(REGISTRO_ENDPOINTS[client_ip]) > LIMITE_ENDPOINTS_DISTINTOS else 0
290
+
291
+ nivel_heuristica = PESO_HEURISTICA * (score_headers + score_endpoints)
292
+
293
+ # 4. CÁLCULO DEL SCORE TOTAL Y DECISIÓN DE MITIGACIÓN
294
+
295
+ S_total = nivel_dos + nivel_blacklist + nivel_heuristica
296
+
297
+ if S_total >= UMBRAL_BLOQUEO:
298
+ descripcion_log = [
299
+ f"Score Total: {S_total:.3f} > Umbral {UMBRAL_BLOQUEO}",
300
+ f"DoS: {nivel_dos:.3f}, Blacklist: {nivel_blacklist:.3f}, Heurística: {nivel_heuristica:.3f}"
301
+ ]
302
+ registrar_evento(
303
+ tipo="Bloqueo por Score Total",
304
+ descripcion=" ; ".join(descripcion_log),
305
+ severidad="CRÍTICA",
306
+ )
307
+ limitar_peticion(usuario_id=client_ip)
308
+ return HttpResponseForbidden("Acceso denegado por alto Score de Amenaza.")
309
+
310
+ # 5. REGISTRO DE ADVERTENCIA (Si no se bloquea, pero es sospechoso)
311
+
312
+ if S_total > UMBRAL_BLOQUEO * 0.75 or (nivel_dos > 0) or len(sospechas_headers) > 0:
313
+
314
+ descripcion = sospechas_headers
315
+ if score_endpoints > 0:
316
+ descripcion.append("Número anormal de endpoints distintos accedidos (posible escaneo/scraping)")
317
+
318
+ descripcion.insert(0, f"Score Total: {S_total:.3f} (Tasa: {tasa} req/min)")
156
319
  descripcion.append(f"Ruta: {path}")
157
320
 
158
321
  logger.warning(
159
- "DoS detectado o sospechoso desde IP %s: %s ; nivel: %.2f",
322
+ "Tráfico Sospechoso desde IP %s: %s",
160
323
  client_ip,
161
- descripcion,
162
- nivel,
324
+ " ; ".join(descripcion),
163
325
  )
164
-
326
+
165
327
  request.dos_attack_info = {
166
328
  "ip": client_ip,
167
- "tipos": ["DoS"],
329
+ "tipos": ["DoS", "Scraping/Escaneo"],
168
330
  "descripcion": descripcion,
169
- "payload": json.dumps(
170
- {"user_agent": user_agent, "referer": referer, "path": path}
171
- ),
172
- "score": nivel,
331
+ "payload": json.dumps({"user_agent": user_agent, "referer": referer, "path": path}),
332
+ "score": S_total,
173
333
  }
174
334
 
175
- return None
176
-
177
-
178
- """
179
- Detector de ataques de tipo DoS (Denial of Service)
180
- ====================================================
181
-
182
- Este módulo forma parte del sistema de detección de amenazas.
183
- Detecta tasas de petición anómalas en base a límites configurables,
184
- captura datos del atacante (IP, agente, cabeceras)
185
- y registra los incidentes para su auditoría.
186
-
187
- Componentes:
188
- - DOSDefenseMiddleware: Middleware principal de detección.
189
- - detectar_dos(): Evalúa si la tasa supera el umbral permitido.
190
- - calcular_nivel_amenaza_dos(): Calcula la severidad proporcional.
191
- - registrar_evento(): Registra los incidentes en auditoría.
192
-
193
- Algoritmos relacionados:
194
- * Rate Limiting basado en ventana deslizante.
195
- * Cálculo de score: S_dos = w_dos * (tasa_peticion / limite)
196
- """
197
-
198
-
199
- """
200
- Algoritmos relacionados:
201
- *Rate Limiting, listas de bloqueo.
202
- *Opcional: cifrado de logs con ChaCha20-Poly1305.
203
- Contribución a fórmula de amenaza S:
204
- S_dos = w_dos * (tasa_peticion / limite)
205
- S_dos = 0.6 * (150 / 100)
206
- donde w_dos es peso asignado a DoS y tasa_peticion / limite es la proporción de la tasa actual sobre el límite.
207
- """
208
- """
209
- Detector de ataques de tipo DoS (Denial of Service)
210
- ====================================================
211
-
212
- Este módulo forma parte del sistema de detección de amenazas.
213
- Detecta tasas de petición anómalas en base a límites configurables,
214
- captura datos del atacante (IP, agente, cabeceras)
215
- y registra los incidentes para su auditoría.
216
-
217
- Componentes:
218
- - DOSDefenseMiddleware: Middleware principal de detección.
219
- - detectar_dos(): Evalúa si la tasa supera el umbral permitido.
220
- - calcular_nivel_amenaza_dos(): Calcula la severidad proporcional.
221
- - registrar_evento(): Registra los incidentes en auditoría.
222
-
223
- Algoritmos relacionados:
224
- * Rate Limiting basado en ventana deslizante.
225
- * Cálculo de score: S_dos = w_dos * (tasa_peticion / limite)
226
- """
335
+ return None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GuardianUnivalle-Benito-Yucra
3
- Version: 0.1.50
3
+ Version: 0.1.51
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
@@ -0,0 +1,13 @@
1
+ GuardianUnivalle_Benito_Yucra/__init__.py,sha256=lbIRb8fCFYfAdyJV6NsYVZJ5pKYSJZKhhK-En9g_1M8,762
2
+ GuardianUnivalle_Benito_Yucra/utilidades.py,sha256=lFNVnlyTSYmQ1CqtmHx6aefK5uNw0wsMdHRQyxAIZy0,120
3
+ GuardianUnivalle_Benito_Yucra/auditoria/registro_auditoria.py,sha256=NnKBOeRWkXVGaMBeQRYU528rWlaBDBPmTAzfji9n8fw,1135
4
+ GuardianUnivalle_Benito_Yucra/detectores/detector_csrf.py,sha256=q7-UsVseTtIYZz4bbpx2X0kzpDmu2Cetm7eYPJtsruA,7608
5
+ GuardianUnivalle_Benito_Yucra/detectores/detector_dos.py,sha256=m5ibalfC5ZVd-Ec8303lfVgxsnupA7FHQGssyhbGB7o,14193
6
+ GuardianUnivalle_Benito_Yucra/detectores/detector_keylogger.py,sha256=L5RQ0Sdgg7hTU1qkZYwt7AcDqtAzT6u-jwBGo7YWfsw,8078
7
+ GuardianUnivalle_Benito_Yucra/detectores/detector_sql.py,sha256=EEbnn5J7sZxnsA2a0cT1VAB4ZS7BMhQiHSeqrR2SU3A,4820
8
+ GuardianUnivalle_Benito_Yucra/detectores/detector_xss.py,sha256=EDxGDaOosFJCyWTS_HkB300qL30ArxAEi-i0cVrzXyU,11027
9
+ guardianunivalle_benito_yucra-0.1.51.dist-info/licenses/LICENSE,sha256=5e4IdL542v1E8Ft0A24GZjrxZeTsVK7XrS3mZEUhPtM,37
10
+ guardianunivalle_benito_yucra-0.1.51.dist-info/METADATA,sha256=-cN5bh7xRQHQ9TqZ5r_-PbhYzF5seAt7-cVW0kPsW2A,1893
11
+ guardianunivalle_benito_yucra-0.1.51.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
12
+ guardianunivalle_benito_yucra-0.1.51.dist-info/top_level.txt,sha256=HTWfZM64WAV_QYr5cnXnLuabQt92dvlxqlR3pCwpbDQ,30
13
+ guardianunivalle_benito_yucra-0.1.51.dist-info/RECORD,,
@@ -1,119 +0,0 @@
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,25 +0,0 @@
1
- """
2
- Cifrado simétrico autenticado: AES-GCM y ChaCha20-Poly1305
3
- """
4
- from cryptography.hazmat.primitives.ciphers.aead import AESGCM, ChaCha20Poly1305
5
- import os
6
-
7
- def cifrar_aes_gcm(mensaje: bytes, clave: bytes) -> dict:
8
- aes = AESGCM(clave)
9
- nonce = os.urandom(12)
10
- ciphertext = aes.encrypt(nonce, mensaje, None)
11
- return {"nonce": nonce, "ciphertext": ciphertext}
12
-
13
- def descifrar_aes_gcm(cipher: dict, clave: bytes) -> bytes:
14
- aes = AESGCM(clave)
15
- return aes.decrypt(cipher["nonce"], cipher["ciphertext"], None)
16
-
17
- def cifrar_chacha20(mensaje: bytes, clave: bytes) -> dict:
18
- cipher = ChaCha20Poly1305(clave)
19
- nonce = os.urandom(12)
20
- ciphertext = cipher.encrypt(nonce, mensaje, None)
21
- return {"nonce": nonce, "ciphertext": ciphertext}
22
-
23
- def descifrar_chacha20(cipher: dict, clave: bytes) -> bytes:
24
- cipher_obj = ChaCha20Poly1305(clave)
25
- return cipher_obj.decrypt(cipher["nonce"], cipher["ciphertext"], None)
@@ -1,23 +0,0 @@
1
- """
2
- Gestión de intercambio de claves con ECDH y derivación HKDF.
3
- """
4
- from cryptography.hazmat.primitives.asymmetric import ec
5
- from cryptography.hazmat.primitives.kdf.hkdf import HKDF
6
- from cryptography.hazmat.primitives import hashes
7
-
8
- def generar_claves_ecdh():
9
- """Genera clave privada y pública ECDH"""
10
- clave_privada = ec.generate_private_key(ec.SECP384R1())
11
- clave_publica = clave_privada.public_key()
12
- return clave_privada, clave_publica
13
-
14
- def derivar_clave_secreta(clave_privada, clave_publica):
15
- """Deriva una clave compartida usando HKDF"""
16
- shared_key = clave_privada.exchange(ec.ECDH(), clave_publica)
17
- derived_key = HKDF(
18
- algorithm=hashes.SHA256(),
19
- length=32,
20
- salt=None,
21
- info=b'guardianclave'
22
- ).derive(shared_key)
23
- return derived_key
@@ -1,23 +0,0 @@
1
- """
2
- Wrappers para derivación de claves segura: PBKDF2 y Argon2
3
- """
4
- from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
5
- from argon2 import PasswordHasher
6
- from cryptography.hazmat.primitives import hashes
7
- import os
8
-
9
- def pbkdf2_derivar_clave(password: str, salt: bytes = None) -> bytes:
10
- """Deriva clave usando PBKDF2"""
11
- salt = salt or os.urandom(16)
12
- kdf = PBKDF2HMAC(
13
- algorithm=hashes.SHA256(),
14
- length=32,
15
- salt=salt,
16
- iterations=100_000,
17
- )
18
- return kdf.derive(password.encode()), salt
19
-
20
- def argon2_derivar_clave(password: str) -> str:
21
- """Deriva clave usando Argon2"""
22
- ph = PasswordHasher()
23
- return ph.hash(password)
@@ -1,13 +0,0 @@
1
- """
2
- Middleware base para frameworks web (Django/Flask/FastAPI)
3
- """
4
- from ..detectores.detector_sql import detectar_inyeccion_sql
5
- from ..detectores.detector_xss import detectar_xss
6
-
7
- def middleware_proteccion(request):
8
- # Simulación de protección de entrada
9
- if detectar_inyeccion_sql(request.get("query", "")):
10
- return {"error": "SQL Injection detectado"}
11
- if detectar_xss(request.get("input", "")):
12
- return {"error": "XSS detectado"}
13
- return {"ok": True}
@@ -1,7 +0,0 @@
1
- """
2
- Limitador de peticiones para prevenir DoS
3
- """
4
- def limitar_peticion(usuario_id: str, max_peticion: int = 100) -> bool:
5
- # Simulación de limitador: True si excede
6
- print(f"✅ Limitador activo para {usuario_id}")
7
- return False
@@ -1,10 +0,0 @@
1
- """
2
- Manejo de lista de bloqueo
3
- """
4
- lista_bloqueo = set()
5
-
6
- def agregar_bloqueo(ip: str):
7
- lista_bloqueo.add(ip)
8
-
9
- def esta_bloqueado(ip: str) -> bool:
10
- return ip in lista_bloqueo
@@ -1,15 +0,0 @@
1
- """
2
- Fórmula compuesta S para puntuar la amenaza global
3
- """
4
- def calcular_puntuacion(detecciones_sql=0, detecciones_xss=0, intentos_csrf=0,
5
- procesos_keylogger=0, tasa_dos=0,
6
- w_sql=1.5, w_xss=1.2, w_csrf=1.0, w_keylogger=2.0, w_dos=2.5,
7
- limite_dos=100) -> float:
8
- S = (
9
- w_sql * detecciones_sql +
10
- w_xss * detecciones_xss +
11
- w_csrf * intentos_csrf +
12
- w_keylogger * procesos_keylogger +
13
- w_dos * (tasa_dos / limite_dos)
14
- )
15
- return S
@@ -1,21 +0,0 @@
1
- GuardianUnivalle_Benito_Yucra/__init__.py,sha256=lbIRb8fCFYfAdyJV6NsYVZJ5pKYSJZKhhK-En9g_1M8,762
2
- GuardianUnivalle_Benito_Yucra/utilidades.py,sha256=lFNVnlyTSYmQ1CqtmHx6aefK5uNw0wsMdHRQyxAIZy0,120
3
- GuardianUnivalle_Benito_Yucra/auditoria/auditoria_servidor.py,sha256=ZXyzegZb_iQI4ICzPBw2uJeco4LMYZ1wv12DuTnKb7M,4543
4
- GuardianUnivalle_Benito_Yucra/auditoria/registro_auditoria.py,sha256=NnKBOeRWkXVGaMBeQRYU528rWlaBDBPmTAzfji9n8fw,1135
5
- GuardianUnivalle_Benito_Yucra/criptografia/cifrado_aead.py,sha256=wfoRpaKvOqPbollNQsDNUNWClYJlXYTKTYvv0qcR6aI,962
6
- GuardianUnivalle_Benito_Yucra/criptografia/intercambio_claves.py,sha256=9djnlzb022hUhrDbQyWz7lWLbkn_vQZ4K7qar1FXYmo,829
7
- GuardianUnivalle_Benito_Yucra/criptografia/kdf.py,sha256=_sbepEY1qHEKga0ExrX2WRg1HeCPY5MC5CfXZWYyl-A,709
8
- GuardianUnivalle_Benito_Yucra/detectores/detector_csrf.py,sha256=q7-UsVseTtIYZz4bbpx2X0kzpDmu2Cetm7eYPJtsruA,7608
9
- GuardianUnivalle_Benito_Yucra/detectores/detector_dos.py,sha256=167mD_OvicP5T-ptUoBBQlNqFbmL8N1o_4oSKbmcf2Q,8594
10
- GuardianUnivalle_Benito_Yucra/detectores/detector_keylogger.py,sha256=L5RQ0Sdgg7hTU1qkZYwt7AcDqtAzT6u-jwBGo7YWfsw,8078
11
- GuardianUnivalle_Benito_Yucra/detectores/detector_sql.py,sha256=EEbnn5J7sZxnsA2a0cT1VAB4ZS7BMhQiHSeqrR2SU3A,4820
12
- GuardianUnivalle_Benito_Yucra/detectores/detector_xss.py,sha256=EDxGDaOosFJCyWTS_HkB300qL30ArxAEi-i0cVrzXyU,11027
13
- GuardianUnivalle_Benito_Yucra/middleware_web/middleware_web.py,sha256=23pLLYqliUoMrIC6ZEwz3hKXeDjWfHSm9vYPWGmDDik,495
14
- GuardianUnivalle_Benito_Yucra/mitigacion/limitador_peticion.py,sha256=ipMOebYhql-6mSyHs0ddYXOcXq9w8P_IXLlpiIqGncw,246
15
- GuardianUnivalle_Benito_Yucra/mitigacion/lista_bloqueo.py,sha256=6AYWII4mrmwCLHCvGTyoBxR4Oasr4raSHpFbVjqn7d8,193
16
- GuardianUnivalle_Benito_Yucra/puntuacion/puntuacion_amenaza.py,sha256=Wx5XfcII4oweLvZsTBEJ7kUc9pMpP5-36RfI5C5KJXo,561
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,,