aiwaf 0.1.7.3__py3-none-any.whl → 0.1.7.6__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 aiwaf might be problematic. Click here for more details.
- aiwaf/middleware.py +31 -24
- {aiwaf-0.1.7.3.dist-info → aiwaf-0.1.7.6.dist-info}/METADATA +1 -1
- {aiwaf-0.1.7.3.dist-info → aiwaf-0.1.7.6.dist-info}/RECORD +6 -6
- {aiwaf-0.1.7.3.dist-info → aiwaf-0.1.7.6.dist-info}/WHEEL +1 -1
- {aiwaf-0.1.7.3.dist-info → aiwaf-0.1.7.6.dist-info}/licenses/LICENSE +0 -0
- {aiwaf-0.1.7.3.dist-info → aiwaf-0.1.7.6.dist-info}/top_level.txt +0 -0
aiwaf/middleware.py
CHANGED
|
@@ -14,7 +14,7 @@ from django.core.cache import cache
|
|
|
14
14
|
from django.db.models import F
|
|
15
15
|
from django.apps import apps
|
|
16
16
|
from django.urls import get_resolver
|
|
17
|
-
|
|
17
|
+
from .trainer import STATIC_KW, STATUS_IDX, is_exempt_path, path_exists_in_django
|
|
18
18
|
from .blacklist_manager import BlacklistManager
|
|
19
19
|
from .models import DynamicKeyword
|
|
20
20
|
|
|
@@ -131,17 +131,45 @@ class AIAnomalyMiddleware(MiddlewareMixin):
|
|
|
131
131
|
WINDOW = getattr(settings, "AIWAF_WINDOW_SECONDS", 60)
|
|
132
132
|
TOP_N = getattr(settings, "AIWAF_DYNAMIC_TOP_N", 10)
|
|
133
133
|
|
|
134
|
+
def __init__(self, get_response=None):
|
|
135
|
+
super().__init__(get_response)
|
|
136
|
+
model_path = os.path.join(os.path.dirname(__file__), "resources", "model.pkl")
|
|
137
|
+
self.model = joblib.load(model_path)
|
|
138
|
+
|
|
134
139
|
def process_request(self, request):
|
|
135
140
|
if is_exempt_path(request.path):
|
|
136
141
|
return None
|
|
142
|
+
request._start_time = time.time()
|
|
137
143
|
ip = get_ip(request)
|
|
138
144
|
if BlacklistManager.is_blocked(ip):
|
|
139
145
|
return JsonResponse({"error": "blocked"}, status=403)
|
|
146
|
+
return None
|
|
140
147
|
|
|
148
|
+
def process_response(self, request, response):
|
|
149
|
+
if is_exempt_path(request.path):
|
|
150
|
+
return response
|
|
151
|
+
ip = get_ip(request)
|
|
141
152
|
now = time.time()
|
|
142
153
|
key = f"aiwaf:{ip}"
|
|
143
154
|
data = cache.get(key, [])
|
|
144
|
-
|
|
155
|
+
path_len = len(request.path)
|
|
156
|
+
if not path_exists_in_django(request.path) and not is_exempt_path(request.path):
|
|
157
|
+
kw_hits = sum(1 for kw in STATIC_KW if kw in request.path.lower())
|
|
158
|
+
else:
|
|
159
|
+
kw_hits = 0
|
|
160
|
+
|
|
161
|
+
resp_time = now - getattr(request, "_start_time", now)
|
|
162
|
+
status_code = str(response.status_code)
|
|
163
|
+
status_idx = STATUS_IDX.index(status_code) if status_code in STATUS_IDX else -1
|
|
164
|
+
burst_count = sum(1 for (t, _, _, _) in data if now - t <= 10)
|
|
165
|
+
total_404 = sum(1 for (_, _, st, _) in data if st == 404)
|
|
166
|
+
feats = [path_len, kw_hits, resp_time, status_idx, burst_count, total_404]
|
|
167
|
+
X = np.array(feats, dtype=float).reshape(1, -1)
|
|
168
|
+
if self.model.predict(X)[0] == -1:
|
|
169
|
+
BlacklistManager.block(ip, "AI anomaly")
|
|
170
|
+
return JsonResponse({"error": "blocked"}, status=403)
|
|
171
|
+
|
|
172
|
+
data.append((now, request.path, response.status_code, resp_time))
|
|
145
173
|
data = [d for d in data if now - d[0] < self.WINDOW]
|
|
146
174
|
cache.set(key, data, timeout=self.WINDOW)
|
|
147
175
|
for seg in re.split(r"\W+", request.path.lower()):
|
|
@@ -149,28 +177,7 @@ class AIAnomalyMiddleware(MiddlewareMixin):
|
|
|
149
177
|
obj, _ = DynamicKeyword.objects.get_or_create(keyword=seg)
|
|
150
178
|
DynamicKeyword.objects.filter(pk=obj.pk).update(count=F("count") + 1)
|
|
151
179
|
|
|
152
|
-
|
|
153
|
-
return None
|
|
154
|
-
top_dynamic = list(
|
|
155
|
-
DynamicKeyword.objects
|
|
156
|
-
.order_by("-count")
|
|
157
|
-
.values_list("keyword", flat=True)[: self.TOP_N]
|
|
158
|
-
)
|
|
159
|
-
ALL_KW = set(STATIC_KW) | set(top_dynamic)
|
|
160
|
-
|
|
161
|
-
total = len(data)
|
|
162
|
-
ratio404 = sum(1 for (_, _, st, _) in data if st == 404) / total
|
|
163
|
-
hits = sum(any(kw in path.lower() for kw in ALL_KW) for (_, path, _, _) in data)
|
|
164
|
-
avg_rt = np.mean([rt for (_, _, _, rt) in data]) if data else 0.0
|
|
165
|
-
ivs = [data[i][0] - data[i - 1][0] for i in range(1, total)]
|
|
166
|
-
avg_iv = np.mean(ivs) if ivs else 0.0
|
|
167
|
-
|
|
168
|
-
X = np.array([[total, ratio404, hits, avg_rt, avg_iv]], dtype=float)
|
|
169
|
-
if MODEL.predict(X)[0] == -1:
|
|
170
|
-
BlacklistManager.block(ip, "AI anomaly")
|
|
171
|
-
return JsonResponse({"error": "blocked"}, status=403)
|
|
172
|
-
|
|
173
|
-
return None
|
|
180
|
+
return response
|
|
174
181
|
|
|
175
182
|
|
|
176
183
|
class HoneypotMiddleware(MiddlewareMixin):
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
aiwaf/__init__.py,sha256=nQFpJ1YpX48snzLjEQCf8zD2YNh8v0b_kPTrXx8uBYc,46
|
|
2
2
|
aiwaf/apps.py,sha256=nCez-Ptlv2kaEk5HenA8b1pATz1VfhrHP1344gwcY1A,142
|
|
3
3
|
aiwaf/blacklist_manager.py,sha256=sM6uTH7zD6MOPGb0kzqV2aFut2vxKgft_UVeRJr7klw,392
|
|
4
|
-
aiwaf/middleware.py,sha256=
|
|
4
|
+
aiwaf/middleware.py,sha256=kH77E1xWVIjQF6frUGM6kdoz-gZXGAh43Fj-2hPEbSM,7990
|
|
5
5
|
aiwaf/models.py,sha256=8au1umopgCo0lthztTTRrYRJQUM7uX8eAeXgs3z45K4,1282
|
|
6
6
|
aiwaf/storage.py,sha256=bxCILzzvA1-q6nwclRE8WrfoRhe25H4VrsQDf0hl_lY,1903
|
|
7
7
|
aiwaf/trainer.py,sha256=ir5kFTeLQuhMd2h094ct03Wr-rNZsX-mZHwjLx29F54,6422
|
|
@@ -12,8 +12,8 @@ aiwaf/management/commands/detect_and_train.py,sha256=-o-LZ7QZ5GeJPCekryox1DGXKMm
|
|
|
12
12
|
aiwaf/resources/model.pkl,sha256=rCCXH38SJrnaOba2WZrU1LQVzWT34x6bTVkq20XJU-Q,1091129
|
|
13
13
|
aiwaf/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
14
|
aiwaf/templatetags/aiwaf_tags.py,sha256=1KGqeioYmgKACDUiPkykSqI7DLQ6-Ypy1k00weWj9iY,399
|
|
15
|
-
aiwaf-0.1.7.
|
|
16
|
-
aiwaf-0.1.7.
|
|
17
|
-
aiwaf-0.1.7.
|
|
18
|
-
aiwaf-0.1.7.
|
|
19
|
-
aiwaf-0.1.7.
|
|
15
|
+
aiwaf-0.1.7.6.dist-info/licenses/LICENSE,sha256=Ir8PX4dxgAcdB0wqNPIkw84fzIIRKE75NoUil9RX0QU,1069
|
|
16
|
+
aiwaf-0.1.7.6.dist-info/METADATA,sha256=wzS_EmYIHPo4JULdOAoVZvWn7Yo2I9qrRkcWkHw-k34,6116
|
|
17
|
+
aiwaf-0.1.7.6.dist-info/WHEEL,sha256=DnLRTWE75wApRYVsjgc6wsVswC54sMSJhAEd4xhDpBk,91
|
|
18
|
+
aiwaf-0.1.7.6.dist-info/top_level.txt,sha256=kU6EyjobT6UPCxuWpI_BvcHDG0I2tMgKaPlWzVxe2xI,6
|
|
19
|
+
aiwaf-0.1.7.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|