GuardianUnivalle-Benito-Yucra 0.1.1__tar.gz → 0.1.3__tar.gz

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.

Files changed (27) hide show
  1. guardianunivalle_benito_yucra-0.1.3/GuardianUnivalle_Benito_Yucra/detectores/detector_sql.py +89 -0
  2. {guardianunivalle_benito_yucra-0.1.1 → guardianunivalle_benito_yucra-0.1.3}/GuardianUnivalle_Benito_Yucra.egg-info/PKG-INFO +14 -2
  3. {guardianunivalle_benito_yucra-0.1.1 → guardianunivalle_benito_yucra-0.1.3}/GuardianUnivalle_Benito_Yucra.egg-info/SOURCES.txt +6 -1
  4. guardianunivalle_benito_yucra-0.1.3/GuardianUnivalle_Benito_Yucra.egg-info/requires.txt +2 -0
  5. {guardianunivalle_benito_yucra-0.1.1 → guardianunivalle_benito_yucra-0.1.3}/PKG-INFO +14 -2
  6. guardianunivalle_benito_yucra-0.1.3/pyproject.toml +36 -0
  7. guardianunivalle_benito_yucra-0.1.1/GuardianUnivalle_Benito_Yucra/detectores/detector_sql.py +0 -192
  8. guardianunivalle_benito_yucra-0.1.1/pyproject.toml +0 -14
  9. {guardianunivalle_benito_yucra-0.1.1 → guardianunivalle_benito_yucra-0.1.3}/GuardianUnivalle_Benito_Yucra/__init__.py +0 -0
  10. {guardianunivalle_benito_yucra-0.1.1 → guardianunivalle_benito_yucra-0.1.3}/GuardianUnivalle_Benito_Yucra/auditoria/registro_auditoria.py +0 -0
  11. {guardianunivalle_benito_yucra-0.1.1 → guardianunivalle_benito_yucra-0.1.3}/GuardianUnivalle_Benito_Yucra/criptografia/cifrado_aead.py +0 -0
  12. {guardianunivalle_benito_yucra-0.1.1 → guardianunivalle_benito_yucra-0.1.3}/GuardianUnivalle_Benito_Yucra/criptografia/intercambio_claves.py +0 -0
  13. {guardianunivalle_benito_yucra-0.1.1 → guardianunivalle_benito_yucra-0.1.3}/GuardianUnivalle_Benito_Yucra/criptografia/kdf.py +0 -0
  14. {guardianunivalle_benito_yucra-0.1.1 → guardianunivalle_benito_yucra-0.1.3}/GuardianUnivalle_Benito_Yucra/detectores/detector_csrf.py +0 -0
  15. {guardianunivalle_benito_yucra-0.1.1 → guardianunivalle_benito_yucra-0.1.3}/GuardianUnivalle_Benito_Yucra/detectores/detector_dos.py +0 -0
  16. {guardianunivalle_benito_yucra-0.1.1 → guardianunivalle_benito_yucra-0.1.3}/GuardianUnivalle_Benito_Yucra/detectores/detector_keylogger.py +0 -0
  17. {guardianunivalle_benito_yucra-0.1.1 → guardianunivalle_benito_yucra-0.1.3}/GuardianUnivalle_Benito_Yucra/detectores/detector_xss.py +0 -0
  18. {guardianunivalle_benito_yucra-0.1.1 → guardianunivalle_benito_yucra-0.1.3}/GuardianUnivalle_Benito_Yucra/middleware_web/middleware_web.py +0 -0
  19. {guardianunivalle_benito_yucra-0.1.1 → guardianunivalle_benito_yucra-0.1.3}/GuardianUnivalle_Benito_Yucra/mitigacion/limitador_peticion.py +0 -0
  20. {guardianunivalle_benito_yucra-0.1.1 → guardianunivalle_benito_yucra-0.1.3}/GuardianUnivalle_Benito_Yucra/mitigacion/lista_bloqueo.py +0 -0
  21. {guardianunivalle_benito_yucra-0.1.1 → guardianunivalle_benito_yucra-0.1.3}/GuardianUnivalle_Benito_Yucra/puntuacion/puntuacion_amenaza.py +0 -0
  22. {guardianunivalle_benito_yucra-0.1.1 → guardianunivalle_benito_yucra-0.1.3}/GuardianUnivalle_Benito_Yucra/utilidades.py +0 -0
  23. {guardianunivalle_benito_yucra-0.1.1 → guardianunivalle_benito_yucra-0.1.3}/GuardianUnivalle_Benito_Yucra.egg-info/dependency_links.txt +0 -0
  24. {guardianunivalle_benito_yucra-0.1.1 → guardianunivalle_benito_yucra-0.1.3}/GuardianUnivalle_Benito_Yucra.egg-info/top_level.txt +0 -0
  25. {guardianunivalle_benito_yucra-0.1.1 → guardianunivalle_benito_yucra-0.1.3}/LICENSE +0 -0
  26. {guardianunivalle_benito_yucra-0.1.1 → guardianunivalle_benito_yucra-0.1.3}/README.md +0 -0
  27. {guardianunivalle_benito_yucra-0.1.1 → guardianunivalle_benito_yucra-0.1.3}/setup.cfg +0 -0
@@ -0,0 +1,89 @@
1
+ # middleware_sql_defense.py
2
+ import re
3
+ import json
4
+ from typing import Tuple
5
+ from django.http import JsonResponse
6
+ from django.utils.deprecation import MiddlewareMixin
7
+
8
+ # ---------- Patrones y normalización ----------
9
+ _literal_single = re.compile(r"'([^'\\]|\\.)*'")
10
+ _literal_double = re.compile(r'"([^"\\]|\\.)*"')
11
+ _comment_sql = re.compile(r"(--[^\n]*|/\*.*?\*/)", re.S)
12
+
13
+ PATTERNS = [
14
+ (re.compile(r"\bunion\b\s+(all\s+)?\bselect\b", re.I), 0.95),
15
+ (re.compile(r"(?<!\w)or(?=\s+1=1)", re.I), 0.99),
16
+ (re.compile(r"\b(select\b.*\bfrom\b.*\bwhere\b.*\b(or|and)\b.*=)", re.I), 0.7),
17
+ (re.compile(r"\b(drop|truncate|delete|insert|update)\b", re.I), 0.8),
18
+ (re.compile(r"(--|#|;)", re.I), 0.4),
19
+ ]
20
+
21
+
22
+ # ---------- Helpers ----------
23
+ def normalize_text(s: str) -> str:
24
+ """Quita literales y comentarios para reducir falsos positivos"""
25
+ if not s:
26
+ return ""
27
+ s = _comment_sql.sub(" ", s)
28
+ s = _literal_single.sub("''", s)
29
+ s = _literal_double.sub('""', s)
30
+ s = re.sub(r"\s+", " ", s).strip()
31
+ return s
32
+
33
+
34
+ def extract_payload_text(request) -> str:
35
+ """Extrae texto potencialmente peligroso del request"""
36
+ parts = []
37
+ try:
38
+ # query params
39
+ if request.META.get("QUERY_STRING"):
40
+ parts.append(request.META.get("QUERY_STRING"))
41
+ # body
42
+ content_type = request.META.get("CONTENT_TYPE", "")
43
+ if "application/json" in content_type:
44
+ try:
45
+ body_json = json.loads(request.body.decode("utf-8") or "{}")
46
+ parts.append(json.dumps(body_json))
47
+ except Exception:
48
+ parts.append((request.body or b"").decode("utf-8", errors="ignore"))
49
+ else:
50
+ try:
51
+ parts.append(request.body.decode("utf-8", errors="ignore"))
52
+ except Exception:
53
+ pass
54
+ # headers sospechosos
55
+ parts.append(request.META.get("HTTP_USER_AGENT", ""))
56
+ parts.append(request.META.get("HTTP_REFERER", ""))
57
+ except Exception:
58
+ pass
59
+ return " ".join([p for p in parts if p])
60
+
61
+
62
+ def detect_sqli_text(text: str) -> Tuple[bool, list]:
63
+ """Detecta patrones en un texto normalizado"""
64
+ q = normalize_text(text)
65
+ matches = []
66
+ for patt, sev in PATTERNS:
67
+ if patt.search(q):
68
+ matches.append((patt.pattern, float(sev)))
69
+ return (len(matches) > 0, matches)
70
+
71
+
72
+ # ---------- Middleware ----------
73
+ class SQLIDefenseMiddleware(MiddlewareMixin):
74
+ def process_request(self, request):
75
+ text = extract_payload_text(request)
76
+ if not text:
77
+ return None
78
+
79
+ flagged, matches = detect_sqli_text(text)
80
+ if flagged:
81
+ # Bloqueo inmediato solo para pruebas
82
+ return JsonResponse(
83
+ {
84
+ "detail": "Request bloqueado: posible inyección SQL detectada",
85
+ "matches": matches,
86
+ },
87
+ status=403,
88
+ )
89
+ return None
@@ -1,12 +1,24 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GuardianUnivalle-Benito-Yucra
3
- Version: 0.1.1
4
- Summary: Librería de seguridad automática para aplicaciones frontend y backend
3
+ Version: 0.1.3
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
7
+ Project-URL: Homepage, https://pypi.org/project/guardianunivalle-benito-yucra/
8
+ Project-URL: Bug_Tracker, https://github.com/Andyyupy/guardianunivalle-benito-yucra/issues
9
+ Keywords: security,django,flask,sqli,xss,csrf,middleware
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Topic :: Security
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Framework :: Django
16
+ Classifier: Framework :: Flask
7
17
  Requires-Python: >=3.8
8
18
  Description-Content-Type: text/markdown
9
19
  License-File: LICENSE
20
+ Requires-Dist: redis>=4.0
21
+ Requires-Dist: django>=3.2
10
22
  Dynamic: license-file
11
23
 
12
24
  <!-- Información de la librería -->
@@ -7,6 +7,7 @@ GuardianUnivalle_Benito_Yucra/utilidades.py
7
7
  GuardianUnivalle_Benito_Yucra.egg-info/PKG-INFO
8
8
  GuardianUnivalle_Benito_Yucra.egg-info/SOURCES.txt
9
9
  GuardianUnivalle_Benito_Yucra.egg-info/dependency_links.txt
10
+ GuardianUnivalle_Benito_Yucra.egg-info/requires.txt
10
11
  GuardianUnivalle_Benito_Yucra.egg-info/top_level.txt
11
12
  GuardianUnivalle_Benito_Yucra/auditoria/registro_auditoria.py
12
13
  GuardianUnivalle_Benito_Yucra/criptografia/cifrado_aead.py
@@ -20,4 +21,8 @@ GuardianUnivalle_Benito_Yucra/detectores/detector_xss.py
20
21
  GuardianUnivalle_Benito_Yucra/middleware_web/middleware_web.py
21
22
  GuardianUnivalle_Benito_Yucra/mitigacion/limitador_peticion.py
22
23
  GuardianUnivalle_Benito_Yucra/mitigacion/lista_bloqueo.py
23
- GuardianUnivalle_Benito_Yucra/puntuacion/puntuacion_amenaza.py
24
+ GuardianUnivalle_Benito_Yucra/puntuacion/puntuacion_amenaza.py
25
+ guardianunivalle_benito_yucra.egg-info/PKG-INFO
26
+ guardianunivalle_benito_yucra.egg-info/SOURCES.txt
27
+ guardianunivalle_benito_yucra.egg-info/dependency_links.txt
28
+ guardianunivalle_benito_yucra.egg-info/top_level.txt
@@ -1,12 +1,24 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GuardianUnivalle-Benito-Yucra
3
- Version: 0.1.1
4
- Summary: Librería de seguridad automática para aplicaciones frontend y backend
3
+ Version: 0.1.3
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
7
+ Project-URL: Homepage, https://pypi.org/project/guardianunivalle-benito-yucra/
8
+ Project-URL: Bug_Tracker, https://github.com/Andyyupy/guardianunivalle-benito-yucra/issues
9
+ Keywords: security,django,flask,sqli,xss,csrf,middleware
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Topic :: Security
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Framework :: Django
16
+ Classifier: Framework :: Flask
7
17
  Requires-Python: >=3.8
8
18
  Description-Content-Type: text/markdown
9
19
  License-File: LICENSE
20
+ Requires-Dist: redis>=4.0
21
+ Requires-Dist: django>=3.2
10
22
  Dynamic: license-file
11
23
 
12
24
  <!-- Información de la librería -->
@@ -0,0 +1,36 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "GuardianUnivalle-Benito-Yucra" # usar mayúsculas consistente
7
+ version = "0.1.3"
8
+ description = "Middleware y detectores de seguridad (SQLi, XSS, CSRF, DoS, Keylogger) para Django/Flask"
9
+ authors = [
10
+ { name = "Andres Benito Calle Yucra", email = "benitoandrescalle035@gmail.com" }
11
+ ]
12
+ readme = "README.md"
13
+ license = { text = "MIT" }
14
+ requires-python = ">=3.8"
15
+ dependencies = [
16
+ "redis>=4.0",
17
+ "django>=3.2"
18
+ ]
19
+ keywords = ["security", "django", "flask", "sqli", "xss", "csrf", "middleware"]
20
+ classifiers = [
21
+ "Development Status :: 3 - Alpha",
22
+ "Intended Audience :: Developers",
23
+ "Topic :: Security",
24
+ "License :: OSI Approved :: MIT License",
25
+ "Programming Language :: Python :: 3",
26
+ "Framework :: Django",
27
+ "Framework :: Flask"
28
+ ]
29
+
30
+ [tool.setuptools.packages.find]
31
+ where = ["."]
32
+ include = ["GuardianUnivalle*"]
33
+
34
+ [project.urls]
35
+ Homepage = "https://pypi.org/project/guardianunivalle-benito-yucra/"
36
+ Bug_Tracker = "https://github.com/Andyyupy/guardianunivalle-benito-yucra/issues"
@@ -1,192 +0,0 @@
1
- # middleware_sql_defense.py
2
- import re
3
- import json
4
- import time
5
- from typing import Tuple
6
- from django.conf import settings
7
- from django.http import JsonResponse
8
- from django.utils.deprecation import MiddlewareMixin
9
- import redis
10
-
11
- # ---------- CONFIGURABLES (poner en settings.py preferiblemente) ----------
12
- W_SQL = getattr(settings, "SQL_DEFENSE_W_SQL", 1.0)
13
- THRESHOLD = getattr(settings, "SQL_DEFENSE_THRESHOLD", 0.8) # score normalizado 0..1
14
- WINDOW_SEC = getattr(
15
- settings, "SQL_DEFENSE_WINDOW_SEC", 300
16
- ) # ventana para conteo (ej. 5min)
17
- MAX_EXPECTED_DETECTIONS = getattr(settings, "SQL_DEFENSE_MAX_EXPECTED_DETECTIONS", 10)
18
- BLOCK_TTL = getattr(
19
- settings, "SQL_DEFENSE_BLOCK_TTL", 600
20
- ) # bloqueo por IP en segundos (ej. 10min)
21
-
22
- REDIS_URL = getattr(settings, "SQL_DEFENSE_REDIS_URL", "redis://localhost:6379/0")
23
- redis_client = redis.from_url(REDIS_URL, decode_responses=True)
24
-
25
- # ---------- Patrones y normalización ----------
26
- _literal_single = re.compile(r"'([^'\\]|\\.)*'")
27
- _literal_double = re.compile(r'"([^"\\]|\\.)*"')
28
- _comment_sql = re.compile(r"(--[^\n]*|/\*.*?\*/)", re.S)
29
-
30
- PATTERNS = [
31
- (re.compile(r"\bunion\b\s+(all\s+)?\bselect\b", re.I), 0.95),
32
- (re.compile(r"(?<!\w)or(?=\s+1=1)", re.I), 0.99),
33
- (re.compile(r"\b(select\b.*\bfrom\b.*\bwhere\b.*\b(or|and)\b.*=)", re.I), 0.7),
34
- (re.compile(r"\b(drop|truncate|delete|insert|update)\b", re.I), 0.8),
35
- (re.compile(r"(--|#|;)", re.I), 0.4),
36
- ]
37
-
38
-
39
- # ---------- Helpers ----------
40
- def get_client_ip(request) -> str:
41
- """Obtiene la IP real (si hay proxies, usa X-Forwarded-For)"""
42
- xff = request.META.get("HTTP_X_FORWARDED_FOR")
43
- if xff:
44
- # X-Forwarded-For puede contener lista de IPs
45
- ip = xff.split(",")[0].strip()
46
- return ip
47
- return request.META.get("REMOTE_ADDR", "")
48
-
49
-
50
- def normalize_text(s: str) -> str:
51
- """Quita literales y comentarios para reducir falsos positivos"""
52
- if not s:
53
- return ""
54
- s = _comment_sql.sub(" ", s)
55
- s = _literal_single.sub("''", s)
56
- s = _literal_double.sub('""', s)
57
- s = re.sub(r"\s+", " ", s).strip()
58
- return s
59
-
60
-
61
- def extract_payload_text(request) -> str:
62
- """
63
- Extrae texto potencialmente peligroso del request:
64
- - query string
65
- - body (JSON o form)
66
- - headers sospechosos (User-Agent, Referer)
67
- """
68
- parts = []
69
- try:
70
- # query params
71
- if request.META.get("QUERY_STRING"):
72
- parts.append(request.META.get("QUERY_STRING"))
73
- # body: intenta json, si no, raw text
74
- content_type = request.META.get("CONTENT_TYPE", "")
75
- if "application/json" in content_type:
76
- try:
77
- body_json = json.loads(request.body.decode("utf-8") or "{}")
78
- parts.append(json.dumps(body_json))
79
- except Exception:
80
- parts.append((request.body or b"").decode("utf-8", errors="ignore"))
81
- else:
82
- # form-encoded or other text
83
- try:
84
- parts.append(request.body.decode("utf-8", errors="ignore"))
85
- except Exception:
86
- pass
87
- # headers
88
- parts.append(request.META.get("HTTP_USER_AGENT", ""))
89
- parts.append(request.META.get("HTTP_REFERER", ""))
90
- except Exception:
91
- pass
92
- return " ".join([p for p in parts if p])
93
-
94
-
95
- def detect_sqli_text(text: str) -> Tuple[bool, list]:
96
- """Detecta patrones en un texto normalizado; devuelve matches con severidad."""
97
- q = normalize_text(text)
98
- matches = []
99
- for patt, sev in PATTERNS:
100
- if patt.search(q):
101
- matches.append((patt.pattern, float(sev)))
102
- return (len(matches) > 0, matches)
103
-
104
-
105
- # ---------- Redis keys ----------
106
- def redis_count_key(ip: str) -> str:
107
- return f"sqli:count:{ip}"
108
-
109
-
110
- def redis_block_key(ip: str) -> str:
111
- return f"sqli:block:{ip}"
112
-
113
-
114
- # ---------- Cálculo de score S_sql/ip ----------
115
- def compute_s_sql_ip(detections_count: int) -> float:
116
- """
117
- Convertir conteo a una puntuación normalizada 0..1.
118
- Usamos saturación en MAX_EXPECTED_DETECTIONS.
119
- """
120
- norm = min(float(detections_count) / float(MAX_EXPECTED_DETECTIONS), 1.0)
121
- score = float(W_SQL) * norm
122
- # Normalizamos a 0..1 si W_SQL puede ser mayor que 1
123
- return min(score, 1.0)
124
-
125
-
126
- # ---------- Middleware ----------
127
- class SQLIDefenseMiddleware(MiddlewareMixin):
128
- def process_request(self, request):
129
- # 1) obtener IP y comprobar si está bloqueada
130
- ip = get_client_ip(request)
131
- if not ip:
132
- return None # no podemos hacer mucho sin IP
133
-
134
- # comprobar bloqueo en Redis
135
- block_key = redis_block_key(ip)
136
- if redis_client.exists(block_key):
137
- ttl = redis_client.ttl(block_key)
138
- return JsonResponse(
139
- {
140
- "detail": "Acceso denegado (bloqueado por actividad sospechosa)",
141
- "block_ttl_s": ttl,
142
- },
143
- status=403,
144
- )
145
-
146
- # 2) extraer texto y detectar patrones
147
- text = extract_payload_text(request)
148
- if not text:
149
- return None
150
-
151
- flagged, matches = detect_sqli_text(text)
152
- if flagged:
153
- # incrementar contador con TTL (ventana)
154
- count_key = redis_count_key(ip)
155
- # INCR y asegurar expiration
156
- new_count = redis_client.incr(count_key)
157
- # establecer TTL si fue creado de nuevo
158
- if redis_client.ttl(count_key) == -1:
159
- redis_client.expire(count_key, WINDOW_SEC)
160
-
161
- # calcular score
162
- current_count = int(new_count)
163
- s_sql_ip = compute_s_sql_ip(current_count)
164
-
165
- # registrar evento (puedes ampliar con logging o envío a SIEM)
166
- # guardamos metadata mínima
167
- event = {
168
- "time": int(time.time()),
169
- "ip": ip,
170
- "count": current_count,
171
- "score": s_sql_ip,
172
- "matches": matches,
173
- }
174
- # Puedes push a lista en Redis o a un logger
175
- redis_client.lpush("sqli:events", json.dumps(event))
176
- redis_client.ltrim("sqli:events", 0, 999) # mantener últimos 1000 eventos
177
-
178
- # Si supera THRESHOLD -> bloquear ip
179
- if s_sql_ip >= float(THRESHOLD):
180
- redis_client.set(redis_block_key(ip), "1", ex=BLOCK_TTL)
181
- # opcional: publicar alerta en canal pubsub o webhook
182
- return JsonResponse(
183
- {"detail": "IP bloqueada por actividad sospechosa", "ip": ip},
184
- status=403,
185
- )
186
- else:
187
- # no bloqueo todavía: permitir continuar pero devolver alerta en header (opcional)
188
- # Puedes añadir header para que la vista/log lo capture
189
- request.META["X-SQLI-ALERT"] = json.dumps(event)
190
- return None
191
-
192
- return None
@@ -1,14 +0,0 @@
1
- [build-system]
2
- requires = ["setuptools>=61.0", "wheel"]
3
- build-backend = "setuptools.build_meta"
4
-
5
- [project]
6
- name = "GuardianUnivalle-Benito-Yucra"
7
- version = "0.1.1"
8
- description = "Librería de seguridad automática para aplicaciones frontend y backend"
9
- authors = [
10
- { name="Andres Benito Calle Yucra", email="benitoandrescalle035@gmail.com" }
11
- ]
12
- readme = "README.md"
13
- license = { text="MIT" }
14
- requires-python = ">=3.8"