aiwaf 0.1.7.8__py3-none-any.whl → 0.1.8.2__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/management/commands/aiwaf_reset.py +84 -0
- aiwaf/middleware.py +29 -8
- aiwaf/templatetags/aiwaf_tags.py +5 -6
- {aiwaf-0.1.7.8.dist-info → aiwaf-0.1.8.2.dist-info}/METADATA +27 -24
- {aiwaf-0.1.7.8.dist-info → aiwaf-0.1.8.2.dist-info}/RECORD +8 -7
- {aiwaf-0.1.7.8.dist-info → aiwaf-0.1.8.2.dist-info}/WHEEL +0 -0
- {aiwaf-0.1.7.8.dist-info → aiwaf-0.1.8.2.dist-info}/licenses/LICENSE +0 -0
- {aiwaf-0.1.7.8.dist-info → aiwaf-0.1.8.2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
from django.core.management.base import BaseCommand
|
|
2
|
+
from aiwaf.models import BlacklistEntry, IPExemption
|
|
3
|
+
|
|
4
|
+
class Command(BaseCommand):
|
|
5
|
+
help = 'Reset AI-WAF by clearing all blacklist and exemption (whitelist) entries'
|
|
6
|
+
|
|
7
|
+
def add_arguments(self, parser):
|
|
8
|
+
parser.add_argument(
|
|
9
|
+
'--blacklist-only',
|
|
10
|
+
action='store_true',
|
|
11
|
+
help='Clear only blacklist entries, keep exemptions'
|
|
12
|
+
)
|
|
13
|
+
parser.add_argument(
|
|
14
|
+
'--exemptions-only',
|
|
15
|
+
action='store_true',
|
|
16
|
+
help='Clear only exemption entries, keep blacklist'
|
|
17
|
+
)
|
|
18
|
+
parser.add_argument(
|
|
19
|
+
'--confirm',
|
|
20
|
+
action='store_true',
|
|
21
|
+
help='Skip confirmation prompt'
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
def handle(self, *args, **options):
|
|
25
|
+
blacklist_only = options['blacklist_only']
|
|
26
|
+
exemptions_only = options['exemptions_only']
|
|
27
|
+
confirm = options['confirm']
|
|
28
|
+
|
|
29
|
+
# Count current entries
|
|
30
|
+
blacklist_count = BlacklistEntry.objects.count()
|
|
31
|
+
exemption_count = IPExemption.objects.count()
|
|
32
|
+
|
|
33
|
+
if blacklist_only and exemptions_only:
|
|
34
|
+
self.stdout.write(self.style.ERROR('Cannot use both --blacklist-only and --exemptions-only flags'))
|
|
35
|
+
return
|
|
36
|
+
|
|
37
|
+
# Determine what to clear
|
|
38
|
+
if blacklist_only:
|
|
39
|
+
action = f"Clear {blacklist_count} blacklist entries"
|
|
40
|
+
clear_blacklist = True
|
|
41
|
+
clear_exemptions = False
|
|
42
|
+
elif exemptions_only:
|
|
43
|
+
action = f"Clear {exemption_count} exemption entries"
|
|
44
|
+
clear_blacklist = False
|
|
45
|
+
clear_exemptions = True
|
|
46
|
+
else:
|
|
47
|
+
action = f"Clear {blacklist_count} blacklist entries and {exemption_count} exemption entries"
|
|
48
|
+
clear_blacklist = True
|
|
49
|
+
clear_exemptions = True
|
|
50
|
+
|
|
51
|
+
# Show what will be cleared
|
|
52
|
+
self.stdout.write(f"AI-WAF Reset: {action}")
|
|
53
|
+
|
|
54
|
+
if not confirm:
|
|
55
|
+
response = input("Are you sure you want to proceed? [y/N]: ")
|
|
56
|
+
if response.lower() not in ['y', 'yes']:
|
|
57
|
+
self.stdout.write(self.style.WARNING('Operation cancelled'))
|
|
58
|
+
return
|
|
59
|
+
|
|
60
|
+
# Perform the reset
|
|
61
|
+
deleted_counts = {'blacklist': 0, 'exemptions': 0}
|
|
62
|
+
|
|
63
|
+
if clear_blacklist:
|
|
64
|
+
deleted_counts['blacklist'], _ = BlacklistEntry.objects.all().delete()
|
|
65
|
+
|
|
66
|
+
if clear_exemptions:
|
|
67
|
+
deleted_counts['exemptions'], _ = IPExemption.objects.all().delete()
|
|
68
|
+
|
|
69
|
+
# Report results
|
|
70
|
+
if clear_blacklist and clear_exemptions:
|
|
71
|
+
self.stdout.write(
|
|
72
|
+
self.style.SUCCESS(
|
|
73
|
+
f"✅ Reset complete: Deleted {deleted_counts['blacklist']} blacklist entries "
|
|
74
|
+
f"and {deleted_counts['exemptions']} exemption entries"
|
|
75
|
+
)
|
|
76
|
+
)
|
|
77
|
+
elif clear_blacklist:
|
|
78
|
+
self.stdout.write(
|
|
79
|
+
self.style.SUCCESS(f"✅ Blacklist cleared: Deleted {deleted_counts['blacklist']} entries")
|
|
80
|
+
)
|
|
81
|
+
elif clear_exemptions:
|
|
82
|
+
self.stdout.write(
|
|
83
|
+
self.style.SUCCESS(f"✅ Exemptions cleared: Deleted {deleted_counts['exemptions']} entries")
|
|
84
|
+
)
|
aiwaf/middleware.py
CHANGED
|
@@ -189,16 +189,37 @@ class AIAnomalyMiddleware(MiddlewareMixin):
|
|
|
189
189
|
return response
|
|
190
190
|
|
|
191
191
|
|
|
192
|
-
class
|
|
193
|
-
|
|
192
|
+
class HoneypotTimingMiddleware(MiddlewareMixin):
|
|
193
|
+
MIN_FORM_TIME = getattr(settings, "AIWAF_MIN_FORM_TIME", 1.0) # seconds
|
|
194
|
+
|
|
195
|
+
def process_request(self, request):
|
|
194
196
|
if is_exempt_path(request.path):
|
|
195
197
|
return None
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
198
|
+
|
|
199
|
+
ip = get_ip(request)
|
|
200
|
+
if is_ip_exempted(ip):
|
|
201
|
+
return None
|
|
202
|
+
|
|
203
|
+
if request.method == "GET":
|
|
204
|
+
# Store timestamp for this IP's GET request
|
|
205
|
+
cache.set(f"honeypot_get:{ip}", time.time(), timeout=300) # 5 min timeout
|
|
206
|
+
|
|
207
|
+
elif request.method == "POST":
|
|
208
|
+
# Check if there was a preceding GET request
|
|
209
|
+
get_time = cache.get(f"honeypot_get:{ip}")
|
|
210
|
+
|
|
211
|
+
if get_time is None:
|
|
212
|
+
# No GET request - likely bot posting directly
|
|
213
|
+
BlacklistManager.block(ip, "Direct POST without GET")
|
|
214
|
+
return JsonResponse({"error": "blocked"}, status=403)
|
|
215
|
+
|
|
216
|
+
# Check timing
|
|
217
|
+
time_diff = time.time() - get_time
|
|
218
|
+
if time_diff < self.MIN_FORM_TIME:
|
|
219
|
+
# Posted too quickly - likely bot
|
|
220
|
+
BlacklistManager.block(ip, f"Form submitted too quickly ({time_diff:.2f}s)")
|
|
221
|
+
return JsonResponse({"error": "blocked"}, status=403)
|
|
222
|
+
|
|
202
223
|
return None
|
|
203
224
|
|
|
204
225
|
|
aiwaf/templatetags/aiwaf_tags.py
CHANGED
|
@@ -6,9 +6,8 @@ register = template.Library()
|
|
|
6
6
|
|
|
7
7
|
@register.simple_tag
|
|
8
8
|
def honeypot_field(field_name=None):
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
)
|
|
9
|
+
"""
|
|
10
|
+
Legacy honeypot field - no longer needed with timing-based honeypot.
|
|
11
|
+
Returns empty string to maintain backward compatibility.
|
|
12
|
+
"""
|
|
13
|
+
return ""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aiwaf
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.8.2
|
|
4
4
|
Summary: AI-powered Web Application Firewall
|
|
5
5
|
Home-page: https://github.com/aayushgauba/aiwaf
|
|
6
6
|
Author: Aayush Gauba
|
|
@@ -77,8 +77,10 @@ aiwaf/
|
|
|
77
77
|
- **File‑Extension Probing Detection**
|
|
78
78
|
Tracks repeated 404s on common extensions (e.g. `.php`, `.asp`) and blocks IPs.
|
|
79
79
|
|
|
80
|
-
- **Honeypot
|
|
81
|
-
|
|
80
|
+
- **Timing-Based Honeypot**
|
|
81
|
+
Tracks GET→POST timing patterns. Blocks IPs that:
|
|
82
|
+
- POST directly without a preceding GET request
|
|
83
|
+
- Submit forms faster than `AIWAF_MIN_FORM_TIME` seconds (default: 1 second)
|
|
82
84
|
|
|
83
85
|
- **UUID Tampering Protection**
|
|
84
86
|
Blocks guessed or invalid UUIDs that don’t resolve to real models.
|
|
@@ -107,6 +109,24 @@ Add an IP to the exemption list using the management command:
|
|
|
107
109
|
python manage.py add_ipexemption <ip-address> --reason "optional reason"
|
|
108
110
|
```
|
|
109
111
|
|
|
112
|
+
### Resetting AI-WAF
|
|
113
|
+
|
|
114
|
+
Clear all blacklist and exemption entries:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
# Clear everything (with confirmation prompt)
|
|
118
|
+
python manage.py aiwaf_reset
|
|
119
|
+
|
|
120
|
+
# Clear everything without confirmation
|
|
121
|
+
python manage.py aiwaf_reset --confirm
|
|
122
|
+
|
|
123
|
+
# Clear only blacklist entries
|
|
124
|
+
python manage.py aiwaf_reset --blacklist-only
|
|
125
|
+
|
|
126
|
+
# Clear only exemption entries
|
|
127
|
+
python manage.py aiwaf_reset --exemptions-only
|
|
128
|
+
```
|
|
129
|
+
|
|
110
130
|
This will ensure the IP is never blocked by AI‑WAF. You can also manage exemptions via the Django admin interface.
|
|
111
131
|
|
|
112
132
|
- **Daily Retraining**
|
|
@@ -143,7 +163,7 @@ AIWAF_ACCESS_LOG = "/var/log/nginx/access.log"
|
|
|
143
163
|
|
|
144
164
|
```python
|
|
145
165
|
AIWAF_MODEL_PATH = BASE_DIR / "aiwaf" / "resources" / "model.pkl"
|
|
146
|
-
|
|
166
|
+
AIWAF_MIN_FORM_TIME = 1.0 # minimum seconds between GET and POST
|
|
147
167
|
AIWAF_RATE_WINDOW = 10 # seconds
|
|
148
168
|
AIWAF_RATE_MAX = 20 # max requests per window
|
|
149
169
|
AIWAF_RATE_FLOOD = 10 # flood threshold
|
|
@@ -171,7 +191,7 @@ MIDDLEWARE = [
|
|
|
171
191
|
"aiwaf.middleware.IPAndKeywordBlockMiddleware",
|
|
172
192
|
"aiwaf.middleware.RateLimitMiddleware",
|
|
173
193
|
"aiwaf.middleware.AIAnomalyMiddleware",
|
|
174
|
-
"aiwaf.middleware.
|
|
194
|
+
"aiwaf.middleware.HoneypotTimingMiddleware",
|
|
175
195
|
"aiwaf.middleware.UUIDTamperMiddleware",
|
|
176
196
|
# ... other middleware ...
|
|
177
197
|
]
|
|
@@ -179,24 +199,7 @@ MIDDLEWARE = [
|
|
|
179
199
|
|
|
180
200
|
---
|
|
181
201
|
|
|
182
|
-
##
|
|
183
|
-
|
|
184
|
-
```django
|
|
185
|
-
{% load aiwaf_tags %}
|
|
186
|
-
|
|
187
|
-
<form method="post">
|
|
188
|
-
{% csrf_token %}
|
|
189
|
-
{% honeypot_field %}
|
|
190
|
-
<!-- your real fields -->
|
|
191
|
-
</form>
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
> Renders a hidden `<input name="hp_field" style="display:none">`.
|
|
195
|
-
> Any non‑empty submission → IP blacklisted.
|
|
196
|
-
|
|
197
|
-
---
|
|
198
|
-
|
|
199
|
-
## 🔁 Running Detection & Training
|
|
202
|
+
## Running Detection & Training
|
|
200
203
|
|
|
201
204
|
```bash
|
|
202
205
|
python manage.py detect_and_train
|
|
@@ -219,7 +222,7 @@ python manage.py detect_and_train
|
|
|
219
222
|
| IPAndKeywordBlockMiddleware | Blocks requests from known blacklisted IPs and Keywords |
|
|
220
223
|
| RateLimitMiddleware | Enforces burst & flood thresholds |
|
|
221
224
|
| AIAnomalyMiddleware | ML‑driven behavior analysis + block on anomaly |
|
|
222
|
-
|
|
|
225
|
+
| HoneypotTimingMiddleware | Detects bots via GET→POST timing analysis |
|
|
223
226
|
| UUIDTamperMiddleware | Blocks guessed/nonexistent UUIDs across all models in an app |
|
|
224
227
|
|
|
225
228
|
---
|
|
@@ -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=0tmOTErZBy524O6gtKKo4liWYiovAVMgxEk91L-ngZk,9246
|
|
5
5
|
aiwaf/models.py,sha256=XaG1pd_oZu3y-fw66u4wblGlWcUY9gvsTNKGD0kQk7Y,1672
|
|
6
6
|
aiwaf/storage.py,sha256=bxCILzzvA1-q6nwclRE8WrfoRhe25H4VrsQDf0hl_lY,1903
|
|
7
7
|
aiwaf/trainer.py,sha256=Xs_AuA7RCa1oyo5-lJYlnRYUiaq-HY2KXAviAdiGnzU,6217
|
|
@@ -9,12 +9,13 @@ aiwaf/utils.py,sha256=RkEUWhhHy6tOk7V0UYv3cN4xhOR_7aBy9bjhwuV2cdA,1436
|
|
|
9
9
|
aiwaf/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
10
|
aiwaf/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
11
|
aiwaf/management/commands/add_ipexemption.py,sha256=LWN21_ydqSjU3_hUnkou4Ciyrk_479zLvcKdWm8hkC0,988
|
|
12
|
+
aiwaf/management/commands/aiwaf_reset.py,sha256=dUTYX6Z6_X3Ft3lqF_McXE7OdKADlQFGFWvjdvFVZFI,3245
|
|
12
13
|
aiwaf/management/commands/detect_and_train.py,sha256=-o-LZ7QZ5GeJPCekryox1DGXKMmFEkwwrcDsiM166K0,269
|
|
13
14
|
aiwaf/resources/model.pkl,sha256=5t6h9BX8yoh2xct85MXOO60jdlWyg1APskUOW0jZE1Y,1288265
|
|
14
15
|
aiwaf/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
-
aiwaf/templatetags/aiwaf_tags.py,sha256=
|
|
16
|
-
aiwaf-0.1.
|
|
17
|
-
aiwaf-0.1.
|
|
18
|
-
aiwaf-0.1.
|
|
19
|
-
aiwaf-0.1.
|
|
20
|
-
aiwaf-0.1.
|
|
16
|
+
aiwaf/templatetags/aiwaf_tags.py,sha256=XXfb7Tl4DjU3Sc40GbqdaqOEtKTUKELBEk58u83wBNw,357
|
|
17
|
+
aiwaf-0.1.8.2.dist-info/licenses/LICENSE,sha256=Ir8PX4dxgAcdB0wqNPIkw84fzIIRKE75NoUil9RX0QU,1069
|
|
18
|
+
aiwaf-0.1.8.2.dist-info/METADATA,sha256=Q93RjqYRrVZ9PwQCHVF2LNgM5bvY1TZxnIgnbPV29-c,7178
|
|
19
|
+
aiwaf-0.1.8.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
20
|
+
aiwaf-0.1.8.2.dist-info/top_level.txt,sha256=kU6EyjobT6UPCxuWpI_BvcHDG0I2tMgKaPlWzVxe2xI,6
|
|
21
|
+
aiwaf-0.1.8.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|