aiwaf 0.1.9.1.9__tar.gz → 0.1.9.2.1__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 aiwaf might be problematic. Click here for more details.
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/PKG-INFO +126 -12
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/README.md +125 -11
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf/__init__.py +1 -1
- aiwaf-0.1.9.2.1/aiwaf/management/commands/aiwaf_reset.py +183 -0
- aiwaf-0.1.9.2.1/aiwaf/middleware.py +621 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf/storage.py +13 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf/trainer.py +184 -9
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf.egg-info/PKG-INFO +126 -12
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/pyproject.toml +1 -1
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/setup.py +1 -1
- aiwaf-0.1.9.1.9/aiwaf/management/commands/aiwaf_reset.py +0 -136
- aiwaf-0.1.9.1.9/aiwaf/middleware.py +0 -352
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/LICENSE +0 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf/apps.py +0 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf/blacklist_manager.py +0 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf/decorators.py +0 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf/management/__init__.py +0 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf/management/commands/__init__.py +0 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf/management/commands/add_exemption.py +0 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf/management/commands/add_ipexemption.py +0 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf/management/commands/aiwaf_diagnose.py +0 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf/management/commands/aiwaf_logging.py +0 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf/management/commands/check_dependencies.py +0 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf/management/commands/clear_blacklist.py +0 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf/management/commands/clear_cache.py +0 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf/management/commands/debug_csv.py +0 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf/management/commands/detect_and_train.py +0 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf/management/commands/diagnose_blocking.py +0 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf/management/commands/regenerate_model.py +0 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf/management/commands/setup_models.py +0 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf/management/commands/test_exemption.py +0 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf/management/commands/test_exemption_fix.py +0 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf/middleware_logger.py +0 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf/models.py +0 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf/resources/model.pkl +0 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf/templatetags/__init__.py +0 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf/templatetags/aiwaf_tags.py +0 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf/utils.py +0 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf.egg-info/SOURCES.txt +0 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf.egg-info/dependency_links.txt +0 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf.egg-info/requires.txt +0 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/aiwaf.egg-info/top_level.txt +0 -0
- {aiwaf-0.1.9.1.9 → aiwaf-0.1.9.2.1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aiwaf
|
|
3
|
-
Version: 0.1.9.1
|
|
3
|
+
Version: 0.1.9.2.1
|
|
4
4
|
Summary: AI-powered Web Application Firewall
|
|
5
5
|
Home-page: https://github.com/aayushgauba/aiwaf
|
|
6
6
|
Author: Aayush Gauba
|
|
@@ -25,7 +25,13 @@ Dynamic: requires-python
|
|
|
25
25
|
# AI‑WAF
|
|
26
26
|
|
|
27
27
|
> A self‑learning, Django‑friendly Web Application Firewall
|
|
28
|
-
> with rate‑limiting, anomaly detection, honeypots, UUID‑tamper protection,
|
|
28
|
+
> with **enhanced context-aware protection**, rate‑limiting, anomaly detection, honeypots, UUID‑tamper protection, **smart keyword learning**, file‑extension probing detection, exempt path awareness, and daily retraining.
|
|
29
|
+
|
|
30
|
+
**🆕 Latest Enhancements:**
|
|
31
|
+
- ✅ **Smart Keyword Filtering** - Prevents blocking legitimate pages like `/profile/`
|
|
32
|
+
- ✅ **Granular Reset Commands** - Clear specific data types (`--blacklist`, `--keywords`, `--exemptions`)
|
|
33
|
+
- ✅ **Context-Aware Learning** - Only learns from suspicious requests, not legitimate site functionality
|
|
34
|
+
- ✅ **Enhanced Configuration** - `AIWAF_ALLOWED_PATH_KEYWORDS` and `AIWAF_EXEMPT_KEYWORDS`
|
|
29
35
|
|
|
30
36
|
---
|
|
31
37
|
|
|
@@ -88,9 +94,19 @@ aiwaf/
|
|
|
88
94
|
- Burst count
|
|
89
95
|
- Total 404s
|
|
90
96
|
|
|
91
|
-
- **Dynamic Keyword
|
|
92
|
-
-
|
|
93
|
-
- **
|
|
97
|
+
- **Enhanced Dynamic Keyword Learning with Django Route Protection**
|
|
98
|
+
- **Smart Context-Aware Learning**: Only learns keywords from suspicious requests on non-existent paths
|
|
99
|
+
- **Automatic Django Route Extraction**: Automatically excludes keywords from:
|
|
100
|
+
- Valid Django URL patterns (`/profile/`, `/admin/`, `/api/`, etc.)
|
|
101
|
+
- Django app names and model names (users, posts, categories)
|
|
102
|
+
- View function names and URL namespaces
|
|
103
|
+
- **Unified Logic**: Both trainer and middleware use identical legitimate keyword detection
|
|
104
|
+
- **Configuration Options**:
|
|
105
|
+
- `AIWAF_ALLOWED_PATH_KEYWORDS` - Explicitly allow certain keywords in legitimate paths
|
|
106
|
+
- `AIWAF_EXEMPT_KEYWORDS` - Keywords that should never trigger blocking
|
|
107
|
+
- **Automatic Cleanup**: Keywords from `AIWAF_EXEMPT_PATHS` are automatically removed from the database
|
|
108
|
+
- **False Positive Prevention**: Stops learning legitimate site functionality as "malicious"
|
|
109
|
+
- **Inherent Malicious Detection**: Middleware also blocks obviously malicious keywords (`hack`, `exploit`, `attack`) even if not yet learned
|
|
94
110
|
|
|
95
111
|
- **File‑Extension Probing Detection**
|
|
96
112
|
Tracks repeated 404s on common extensions (e.g. `.php`, `.asp`) and blocks IPs.
|
|
@@ -196,20 +212,44 @@ python manage.py add_ipexemption <ip-address> --reason "optional reason"
|
|
|
196
212
|
|
|
197
213
|
### Resetting AI-WAF
|
|
198
214
|
|
|
199
|
-
|
|
215
|
+
The `aiwaf_reset` command provides **granular control** for clearing different types of data:
|
|
200
216
|
|
|
201
217
|
```bash
|
|
202
|
-
# Clear everything (
|
|
218
|
+
# Clear everything (default - backward compatible)
|
|
203
219
|
python manage.py aiwaf_reset
|
|
204
220
|
|
|
205
|
-
# Clear everything without confirmation
|
|
221
|
+
# Clear everything without confirmation prompt
|
|
206
222
|
python manage.py aiwaf_reset --confirm
|
|
207
223
|
|
|
208
|
-
# Clear
|
|
209
|
-
python manage.py aiwaf_reset --blacklist
|
|
224
|
+
# 🆕 GRANULAR CONTROL - Clear specific data types
|
|
225
|
+
python manage.py aiwaf_reset --blacklist # Clear only blocked IPs
|
|
226
|
+
python manage.py aiwaf_reset --exemptions # Clear only exempted IPs
|
|
227
|
+
python manage.py aiwaf_reset --keywords # Clear only learned keywords
|
|
228
|
+
|
|
229
|
+
# 🔧 COMBINE OPTIONS - Mix and match as needed
|
|
230
|
+
python manage.py aiwaf_reset --blacklist --keywords # Keep exemptions
|
|
231
|
+
python manage.py aiwaf_reset --exemptions --keywords # Keep blacklist
|
|
232
|
+
python manage.py aiwaf_reset --blacklist --exemptions # Keep keywords
|
|
233
|
+
|
|
234
|
+
# 🚀 COMMON USE CASES
|
|
235
|
+
# Fix false positive keywords (like "profile" blocking legitimate pages)
|
|
236
|
+
python manage.py aiwaf_reset --keywords --confirm
|
|
237
|
+
python manage.py detect_and_train # Retrain with enhanced filtering
|
|
238
|
+
|
|
239
|
+
# Clear blocked IPs but preserve exemptions and learning
|
|
240
|
+
python manage.py aiwaf_reset --blacklist --confirm
|
|
241
|
+
|
|
242
|
+
# Legacy support (still works for backward compatibility)
|
|
243
|
+
python manage.py aiwaf_reset --blacklist-only # Legacy: blacklist only
|
|
244
|
+
python manage.py aiwaf_reset --exemptions-only # Legacy: exemptions only
|
|
245
|
+
```
|
|
210
246
|
|
|
211
|
-
|
|
212
|
-
|
|
247
|
+
**Enhanced Feedback:**
|
|
248
|
+
```bash
|
|
249
|
+
$ python manage.py aiwaf_reset --keywords
|
|
250
|
+
🔧 AI-WAF Reset: Clear 15 learned keywords
|
|
251
|
+
Are you sure you want to proceed? [y/N]: y
|
|
252
|
+
✅ Reset complete: Deleted 15 learned keywords
|
|
213
253
|
```
|
|
214
254
|
|
|
215
255
|
### Checking Dependencies
|
|
@@ -482,6 +522,21 @@ AIWAF_EXEMPT_PATHS = [ # optional but highly recommended
|
|
|
482
522
|
"/media/",
|
|
483
523
|
"/health/",
|
|
484
524
|
]
|
|
525
|
+
|
|
526
|
+
# 🆕 ENHANCED KEYWORD FILTERING OPTIONS
|
|
527
|
+
AIWAF_ALLOWED_PATH_KEYWORDS = [ # Keywords allowed in legitimate paths
|
|
528
|
+
"profile", "user", "account", "settings", "dashboard",
|
|
529
|
+
"admin", "api", "auth", "search", "contact", "about",
|
|
530
|
+
# Add your site-specific legitimate keywords
|
|
531
|
+
"buddycraft", "sc2", "starcraft", # Example: gaming site keywords
|
|
532
|
+
]
|
|
533
|
+
|
|
534
|
+
AIWAF_EXEMPT_KEYWORDS = [ # Keywords that never trigger blocking
|
|
535
|
+
"api", "webhook", "health", "static", "media",
|
|
536
|
+
"upload", "download", "backup", "profile"
|
|
537
|
+
]
|
|
538
|
+
|
|
539
|
+
AIWAF_DYNAMIC_TOP_N = 10 # Number of dynamic keywords to learn (default: 10)
|
|
485
540
|
```
|
|
486
541
|
|
|
487
542
|
> **Note:** You no longer need to define `AIWAF_MALICIOUS_KEYWORDS` or `AIWAF_STATUS_CODES` — they evolve dynamically.
|
|
@@ -680,6 +735,65 @@ python manage.py detect_and_train
|
|
|
680
735
|
|
|
681
736
|
---
|
|
682
737
|
|
|
738
|
+
## 🔧 Troubleshooting
|
|
739
|
+
|
|
740
|
+
### Legitimate Pages Being Blocked
|
|
741
|
+
|
|
742
|
+
**Problem**: Users can't access legitimate pages like `/en/profile/` due to keyword blocking.
|
|
743
|
+
|
|
744
|
+
**Cause**: AIWAF learned legitimate keywords (like "profile") as suspicious from previous traffic.
|
|
745
|
+
|
|
746
|
+
**Solution**:
|
|
747
|
+
```bash
|
|
748
|
+
# 1. Clear problematic learned keywords
|
|
749
|
+
python manage.py aiwaf_reset --keywords --confirm
|
|
750
|
+
|
|
751
|
+
# 2. Add legitimate keywords to settings
|
|
752
|
+
# In settings.py:
|
|
753
|
+
AIWAF_ALLOWED_PATH_KEYWORDS = [
|
|
754
|
+
"profile", "user", "account", "dashboard",
|
|
755
|
+
# Add your site-specific keywords
|
|
756
|
+
]
|
|
757
|
+
|
|
758
|
+
# 3. Retrain with enhanced filtering (won't learn legitimate keywords)
|
|
759
|
+
python manage.py detect_and_train
|
|
760
|
+
|
|
761
|
+
# 4. Test - legitimate pages should now work!
|
|
762
|
+
```
|
|
763
|
+
|
|
764
|
+
### Preventing Future False Positives
|
|
765
|
+
|
|
766
|
+
Configure AIWAF to recognize your site's legitimate keywords:
|
|
767
|
+
|
|
768
|
+
```python
|
|
769
|
+
# settings.py
|
|
770
|
+
AIWAF_ALLOWED_PATH_KEYWORDS = [
|
|
771
|
+
# Common legitimate keywords
|
|
772
|
+
"profile", "user", "account", "settings", "dashboard",
|
|
773
|
+
"admin", "search", "contact", "about", "help",
|
|
774
|
+
|
|
775
|
+
# Your site-specific keywords
|
|
776
|
+
"buddycraft", "sc2", "starcraft", # Gaming site example
|
|
777
|
+
"shop", "cart", "checkout", # E-commerce example
|
|
778
|
+
"blog", "article", "news", # Content site example
|
|
779
|
+
]
|
|
780
|
+
```
|
|
781
|
+
|
|
782
|
+
### Reset Command Options
|
|
783
|
+
|
|
784
|
+
```bash
|
|
785
|
+
# Clear everything (safest for troubleshooting)
|
|
786
|
+
python manage.py aiwaf_reset --confirm
|
|
787
|
+
|
|
788
|
+
# Clear only problematic keywords
|
|
789
|
+
python manage.py aiwaf_reset --keywords --confirm
|
|
790
|
+
|
|
791
|
+
# Clear blocked IPs but keep exemptions
|
|
792
|
+
python manage.py aiwaf_reset --blacklist --confirm
|
|
793
|
+
```
|
|
794
|
+
|
|
795
|
+
---
|
|
796
|
+
|
|
683
797
|
## 🧠 How It Works
|
|
684
798
|
|
|
685
799
|
| Middleware | Purpose |
|
|
@@ -2,7 +2,13 @@
|
|
|
2
2
|
# AI‑WAF
|
|
3
3
|
|
|
4
4
|
> A self‑learning, Django‑friendly Web Application Firewall
|
|
5
|
-
> with rate‑limiting, anomaly detection, honeypots, UUID‑tamper protection,
|
|
5
|
+
> with **enhanced context-aware protection**, rate‑limiting, anomaly detection, honeypots, UUID‑tamper protection, **smart keyword learning**, file‑extension probing detection, exempt path awareness, and daily retraining.
|
|
6
|
+
|
|
7
|
+
**🆕 Latest Enhancements:**
|
|
8
|
+
- ✅ **Smart Keyword Filtering** - Prevents blocking legitimate pages like `/profile/`
|
|
9
|
+
- ✅ **Granular Reset Commands** - Clear specific data types (`--blacklist`, `--keywords`, `--exemptions`)
|
|
10
|
+
- ✅ **Context-Aware Learning** - Only learns from suspicious requests, not legitimate site functionality
|
|
11
|
+
- ✅ **Enhanced Configuration** - `AIWAF_ALLOWED_PATH_KEYWORDS` and `AIWAF_EXEMPT_KEYWORDS`
|
|
6
12
|
|
|
7
13
|
---
|
|
8
14
|
|
|
@@ -65,9 +71,19 @@ aiwaf/
|
|
|
65
71
|
- Burst count
|
|
66
72
|
- Total 404s
|
|
67
73
|
|
|
68
|
-
- **Dynamic Keyword
|
|
69
|
-
-
|
|
70
|
-
- **
|
|
74
|
+
- **Enhanced Dynamic Keyword Learning with Django Route Protection**
|
|
75
|
+
- **Smart Context-Aware Learning**: Only learns keywords from suspicious requests on non-existent paths
|
|
76
|
+
- **Automatic Django Route Extraction**: Automatically excludes keywords from:
|
|
77
|
+
- Valid Django URL patterns (`/profile/`, `/admin/`, `/api/`, etc.)
|
|
78
|
+
- Django app names and model names (users, posts, categories)
|
|
79
|
+
- View function names and URL namespaces
|
|
80
|
+
- **Unified Logic**: Both trainer and middleware use identical legitimate keyword detection
|
|
81
|
+
- **Configuration Options**:
|
|
82
|
+
- `AIWAF_ALLOWED_PATH_KEYWORDS` - Explicitly allow certain keywords in legitimate paths
|
|
83
|
+
- `AIWAF_EXEMPT_KEYWORDS` - Keywords that should never trigger blocking
|
|
84
|
+
- **Automatic Cleanup**: Keywords from `AIWAF_EXEMPT_PATHS` are automatically removed from the database
|
|
85
|
+
- **False Positive Prevention**: Stops learning legitimate site functionality as "malicious"
|
|
86
|
+
- **Inherent Malicious Detection**: Middleware also blocks obviously malicious keywords (`hack`, `exploit`, `attack`) even if not yet learned
|
|
71
87
|
|
|
72
88
|
- **File‑Extension Probing Detection**
|
|
73
89
|
Tracks repeated 404s on common extensions (e.g. `.php`, `.asp`) and blocks IPs.
|
|
@@ -173,20 +189,44 @@ python manage.py add_ipexemption <ip-address> --reason "optional reason"
|
|
|
173
189
|
|
|
174
190
|
### Resetting AI-WAF
|
|
175
191
|
|
|
176
|
-
|
|
192
|
+
The `aiwaf_reset` command provides **granular control** for clearing different types of data:
|
|
177
193
|
|
|
178
194
|
```bash
|
|
179
|
-
# Clear everything (
|
|
195
|
+
# Clear everything (default - backward compatible)
|
|
180
196
|
python manage.py aiwaf_reset
|
|
181
197
|
|
|
182
|
-
# Clear everything without confirmation
|
|
198
|
+
# Clear everything without confirmation prompt
|
|
183
199
|
python manage.py aiwaf_reset --confirm
|
|
184
200
|
|
|
185
|
-
# Clear
|
|
186
|
-
python manage.py aiwaf_reset --blacklist
|
|
201
|
+
# 🆕 GRANULAR CONTROL - Clear specific data types
|
|
202
|
+
python manage.py aiwaf_reset --blacklist # Clear only blocked IPs
|
|
203
|
+
python manage.py aiwaf_reset --exemptions # Clear only exempted IPs
|
|
204
|
+
python manage.py aiwaf_reset --keywords # Clear only learned keywords
|
|
205
|
+
|
|
206
|
+
# 🔧 COMBINE OPTIONS - Mix and match as needed
|
|
207
|
+
python manage.py aiwaf_reset --blacklist --keywords # Keep exemptions
|
|
208
|
+
python manage.py aiwaf_reset --exemptions --keywords # Keep blacklist
|
|
209
|
+
python manage.py aiwaf_reset --blacklist --exemptions # Keep keywords
|
|
210
|
+
|
|
211
|
+
# 🚀 COMMON USE CASES
|
|
212
|
+
# Fix false positive keywords (like "profile" blocking legitimate pages)
|
|
213
|
+
python manage.py aiwaf_reset --keywords --confirm
|
|
214
|
+
python manage.py detect_and_train # Retrain with enhanced filtering
|
|
215
|
+
|
|
216
|
+
# Clear blocked IPs but preserve exemptions and learning
|
|
217
|
+
python manage.py aiwaf_reset --blacklist --confirm
|
|
218
|
+
|
|
219
|
+
# Legacy support (still works for backward compatibility)
|
|
220
|
+
python manage.py aiwaf_reset --blacklist-only # Legacy: blacklist only
|
|
221
|
+
python manage.py aiwaf_reset --exemptions-only # Legacy: exemptions only
|
|
222
|
+
```
|
|
187
223
|
|
|
188
|
-
|
|
189
|
-
|
|
224
|
+
**Enhanced Feedback:**
|
|
225
|
+
```bash
|
|
226
|
+
$ python manage.py aiwaf_reset --keywords
|
|
227
|
+
🔧 AI-WAF Reset: Clear 15 learned keywords
|
|
228
|
+
Are you sure you want to proceed? [y/N]: y
|
|
229
|
+
✅ Reset complete: Deleted 15 learned keywords
|
|
190
230
|
```
|
|
191
231
|
|
|
192
232
|
### Checking Dependencies
|
|
@@ -459,6 +499,21 @@ AIWAF_EXEMPT_PATHS = [ # optional but highly recommended
|
|
|
459
499
|
"/media/",
|
|
460
500
|
"/health/",
|
|
461
501
|
]
|
|
502
|
+
|
|
503
|
+
# 🆕 ENHANCED KEYWORD FILTERING OPTIONS
|
|
504
|
+
AIWAF_ALLOWED_PATH_KEYWORDS = [ # Keywords allowed in legitimate paths
|
|
505
|
+
"profile", "user", "account", "settings", "dashboard",
|
|
506
|
+
"admin", "api", "auth", "search", "contact", "about",
|
|
507
|
+
# Add your site-specific legitimate keywords
|
|
508
|
+
"buddycraft", "sc2", "starcraft", # Example: gaming site keywords
|
|
509
|
+
]
|
|
510
|
+
|
|
511
|
+
AIWAF_EXEMPT_KEYWORDS = [ # Keywords that never trigger blocking
|
|
512
|
+
"api", "webhook", "health", "static", "media",
|
|
513
|
+
"upload", "download", "backup", "profile"
|
|
514
|
+
]
|
|
515
|
+
|
|
516
|
+
AIWAF_DYNAMIC_TOP_N = 10 # Number of dynamic keywords to learn (default: 10)
|
|
462
517
|
```
|
|
463
518
|
|
|
464
519
|
> **Note:** You no longer need to define `AIWAF_MALICIOUS_KEYWORDS` or `AIWAF_STATUS_CODES` — they evolve dynamically.
|
|
@@ -657,6 +712,65 @@ python manage.py detect_and_train
|
|
|
657
712
|
|
|
658
713
|
---
|
|
659
714
|
|
|
715
|
+
## 🔧 Troubleshooting
|
|
716
|
+
|
|
717
|
+
### Legitimate Pages Being Blocked
|
|
718
|
+
|
|
719
|
+
**Problem**: Users can't access legitimate pages like `/en/profile/` due to keyword blocking.
|
|
720
|
+
|
|
721
|
+
**Cause**: AIWAF learned legitimate keywords (like "profile") as suspicious from previous traffic.
|
|
722
|
+
|
|
723
|
+
**Solution**:
|
|
724
|
+
```bash
|
|
725
|
+
# 1. Clear problematic learned keywords
|
|
726
|
+
python manage.py aiwaf_reset --keywords --confirm
|
|
727
|
+
|
|
728
|
+
# 2. Add legitimate keywords to settings
|
|
729
|
+
# In settings.py:
|
|
730
|
+
AIWAF_ALLOWED_PATH_KEYWORDS = [
|
|
731
|
+
"profile", "user", "account", "dashboard",
|
|
732
|
+
# Add your site-specific keywords
|
|
733
|
+
]
|
|
734
|
+
|
|
735
|
+
# 3. Retrain with enhanced filtering (won't learn legitimate keywords)
|
|
736
|
+
python manage.py detect_and_train
|
|
737
|
+
|
|
738
|
+
# 4. Test - legitimate pages should now work!
|
|
739
|
+
```
|
|
740
|
+
|
|
741
|
+
### Preventing Future False Positives
|
|
742
|
+
|
|
743
|
+
Configure AIWAF to recognize your site's legitimate keywords:
|
|
744
|
+
|
|
745
|
+
```python
|
|
746
|
+
# settings.py
|
|
747
|
+
AIWAF_ALLOWED_PATH_KEYWORDS = [
|
|
748
|
+
# Common legitimate keywords
|
|
749
|
+
"profile", "user", "account", "settings", "dashboard",
|
|
750
|
+
"admin", "search", "contact", "about", "help",
|
|
751
|
+
|
|
752
|
+
# Your site-specific keywords
|
|
753
|
+
"buddycraft", "sc2", "starcraft", # Gaming site example
|
|
754
|
+
"shop", "cart", "checkout", # E-commerce example
|
|
755
|
+
"blog", "article", "news", # Content site example
|
|
756
|
+
]
|
|
757
|
+
```
|
|
758
|
+
|
|
759
|
+
### Reset Command Options
|
|
760
|
+
|
|
761
|
+
```bash
|
|
762
|
+
# Clear everything (safest for troubleshooting)
|
|
763
|
+
python manage.py aiwaf_reset --confirm
|
|
764
|
+
|
|
765
|
+
# Clear only problematic keywords
|
|
766
|
+
python manage.py aiwaf_reset --keywords --confirm
|
|
767
|
+
|
|
768
|
+
# Clear blocked IPs but keep exemptions
|
|
769
|
+
python manage.py aiwaf_reset --blacklist --confirm
|
|
770
|
+
```
|
|
771
|
+
|
|
772
|
+
---
|
|
773
|
+
|
|
660
774
|
## 🧠 How It Works
|
|
661
775
|
|
|
662
776
|
| Middleware | Purpose |
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
from django.core.management.base import BaseCommand
|
|
2
|
+
from aiwaf.storage import get_blacklist_store, get_exemption_store, get_keyword_store
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
class Command(BaseCommand):
|
|
6
|
+
help = 'Reset AI-WAF by clearing blacklist, exemption, and/or keyword entries'
|
|
7
|
+
|
|
8
|
+
def add_arguments(self, parser):
|
|
9
|
+
parser.add_argument(
|
|
10
|
+
'--blacklist',
|
|
11
|
+
action='store_true',
|
|
12
|
+
help='Clear blacklist entries (default: all)'
|
|
13
|
+
)
|
|
14
|
+
parser.add_argument(
|
|
15
|
+
'--exemptions',
|
|
16
|
+
action='store_true',
|
|
17
|
+
help='Clear exemption entries (default: all)'
|
|
18
|
+
)
|
|
19
|
+
parser.add_argument(
|
|
20
|
+
'--keywords',
|
|
21
|
+
action='store_true',
|
|
22
|
+
help='Clear learned dynamic keywords (default: all)'
|
|
23
|
+
)
|
|
24
|
+
parser.add_argument(
|
|
25
|
+
'--confirm',
|
|
26
|
+
action='store_true',
|
|
27
|
+
help='Skip confirmation prompt'
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
# Legacy flags for backward compatibility
|
|
31
|
+
parser.add_argument(
|
|
32
|
+
'--blacklist-only',
|
|
33
|
+
action='store_true',
|
|
34
|
+
help='(Legacy) Clear only blacklist entries'
|
|
35
|
+
)
|
|
36
|
+
parser.add_argument(
|
|
37
|
+
'--exemptions-only',
|
|
38
|
+
action='store_true',
|
|
39
|
+
help='(Legacy) Clear only exemption entries'
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
def handle(self, *args, **options):
|
|
43
|
+
# Parse arguments
|
|
44
|
+
blacklist_flag = options.get('blacklist', False)
|
|
45
|
+
exemptions_flag = options.get('exemptions', False)
|
|
46
|
+
keywords_flag = options.get('keywords', False)
|
|
47
|
+
confirm = options.get('confirm', False)
|
|
48
|
+
|
|
49
|
+
# Legacy support
|
|
50
|
+
blacklist_only = options.get('blacklist_only', False)
|
|
51
|
+
exemptions_only = options.get('exemptions_only', False)
|
|
52
|
+
|
|
53
|
+
# Handle legacy flags
|
|
54
|
+
if blacklist_only:
|
|
55
|
+
blacklist_flag = True
|
|
56
|
+
exemptions_flag = False
|
|
57
|
+
keywords_flag = False
|
|
58
|
+
elif exemptions_only:
|
|
59
|
+
blacklist_flag = False
|
|
60
|
+
exemptions_flag = True
|
|
61
|
+
keywords_flag = False
|
|
62
|
+
|
|
63
|
+
# If no specific flags, clear everything
|
|
64
|
+
if not (blacklist_flag or exemptions_flag or keywords_flag):
|
|
65
|
+
blacklist_flag = exemptions_flag = keywords_flag = True
|
|
66
|
+
|
|
67
|
+
try:
|
|
68
|
+
blacklist_store = get_blacklist_store()
|
|
69
|
+
exemption_store = get_exemption_store()
|
|
70
|
+
keyword_store = get_keyword_store()
|
|
71
|
+
except Exception as e:
|
|
72
|
+
self.stdout.write(self.style.ERROR(f'Error initializing stores: {e}'))
|
|
73
|
+
return
|
|
74
|
+
|
|
75
|
+
# Count current entries safely
|
|
76
|
+
counts = {'blacklist': 0, 'exemptions': 0, 'keywords': 0}
|
|
77
|
+
entries = {'blacklist': [], 'exemptions': [], 'keywords': []}
|
|
78
|
+
|
|
79
|
+
if blacklist_flag:
|
|
80
|
+
try:
|
|
81
|
+
entries['blacklist'] = blacklist_store.get_all()
|
|
82
|
+
counts['blacklist'] = len(entries['blacklist'])
|
|
83
|
+
except Exception as e:
|
|
84
|
+
self.stdout.write(self.style.WARNING(f'Warning: Could not count blacklist entries: {e}'))
|
|
85
|
+
|
|
86
|
+
if exemptions_flag:
|
|
87
|
+
try:
|
|
88
|
+
entries['exemptions'] = exemption_store.get_all()
|
|
89
|
+
counts['exemptions'] = len(entries['exemptions'])
|
|
90
|
+
except Exception as e:
|
|
91
|
+
self.stdout.write(self.style.WARNING(f'Warning: Could not count exemption entries: {e}'))
|
|
92
|
+
|
|
93
|
+
if keywords_flag:
|
|
94
|
+
try:
|
|
95
|
+
entries['keywords'] = keyword_store.get_all_keywords()
|
|
96
|
+
counts['keywords'] = len(entries['keywords'])
|
|
97
|
+
except Exception as e:
|
|
98
|
+
self.stdout.write(self.style.WARNING(f'Warning: Could not count keyword entries: {e}'))
|
|
99
|
+
|
|
100
|
+
# Build action description
|
|
101
|
+
actions = []
|
|
102
|
+
if blacklist_flag:
|
|
103
|
+
actions.append(f"{counts['blacklist']} blacklist entries")
|
|
104
|
+
if exemptions_flag:
|
|
105
|
+
actions.append(f"{counts['exemptions']} exemption entries")
|
|
106
|
+
if keywords_flag:
|
|
107
|
+
actions.append(f"{counts['keywords']} learned keywords")
|
|
108
|
+
|
|
109
|
+
action = "Clear " + ", ".join(actions)
|
|
110
|
+
|
|
111
|
+
# Show what will be cleared
|
|
112
|
+
self.stdout.write(f"🔧 AI-WAF Reset: {action}")
|
|
113
|
+
|
|
114
|
+
if not confirm:
|
|
115
|
+
try:
|
|
116
|
+
response = input("Are you sure you want to proceed? [y/N]: ")
|
|
117
|
+
if response.lower() not in ['y', 'yes']:
|
|
118
|
+
self.stdout.write(self.style.WARNING('Operation cancelled'))
|
|
119
|
+
return
|
|
120
|
+
except (EOFError, KeyboardInterrupt):
|
|
121
|
+
self.stdout.write(self.style.WARNING('\nOperation cancelled'))
|
|
122
|
+
return
|
|
123
|
+
|
|
124
|
+
# Perform the reset
|
|
125
|
+
deleted_counts = {'blacklist': 0, 'exemptions': 0, 'keywords': 0, 'errors': []}
|
|
126
|
+
|
|
127
|
+
if blacklist_flag:
|
|
128
|
+
# Clear blacklist entries
|
|
129
|
+
try:
|
|
130
|
+
for entry in entries['blacklist']:
|
|
131
|
+
try:
|
|
132
|
+
blacklist_store.remove_ip(entry['ip_address'])
|
|
133
|
+
deleted_counts['blacklist'] += 1
|
|
134
|
+
except Exception as e:
|
|
135
|
+
deleted_counts['errors'].append(f"Error removing blacklist IP {entry.get('ip_address', 'unknown')}: {e}")
|
|
136
|
+
except Exception as e:
|
|
137
|
+
deleted_counts['errors'].append(f"Error clearing blacklist: {e}")
|
|
138
|
+
|
|
139
|
+
if exemptions_flag:
|
|
140
|
+
# Clear exemption entries
|
|
141
|
+
try:
|
|
142
|
+
for entry in entries['exemptions']:
|
|
143
|
+
try:
|
|
144
|
+
exemption_store.remove_ip(entry['ip_address'])
|
|
145
|
+
deleted_counts['exemptions'] += 1
|
|
146
|
+
except Exception as e:
|
|
147
|
+
deleted_counts['errors'].append(f"Error removing exemption IP {entry.get('ip_address', 'unknown')}: {e}")
|
|
148
|
+
except Exception as e:
|
|
149
|
+
deleted_counts['errors'].append(f"Error clearing exemptions: {e}")
|
|
150
|
+
|
|
151
|
+
if keywords_flag:
|
|
152
|
+
# Clear keyword entries
|
|
153
|
+
try:
|
|
154
|
+
for keyword in entries['keywords']:
|
|
155
|
+
try:
|
|
156
|
+
keyword_store.remove_keyword(keyword)
|
|
157
|
+
deleted_counts['keywords'] += 1
|
|
158
|
+
except Exception as e:
|
|
159
|
+
deleted_counts['errors'].append(f"Error removing keyword '{keyword}': {e}")
|
|
160
|
+
except Exception as e:
|
|
161
|
+
deleted_counts['errors'].append(f"Error clearing keywords: {e}")
|
|
162
|
+
|
|
163
|
+
# Report results
|
|
164
|
+
if deleted_counts['errors']:
|
|
165
|
+
for error in deleted_counts['errors']:
|
|
166
|
+
self.stdout.write(self.style.WARNING(f"⚠️ {error}"))
|
|
167
|
+
|
|
168
|
+
# Build success message
|
|
169
|
+
success_parts = []
|
|
170
|
+
if blacklist_flag:
|
|
171
|
+
success_parts.append(f"{deleted_counts['blacklist']} blacklist entries")
|
|
172
|
+
if exemptions_flag:
|
|
173
|
+
success_parts.append(f"{deleted_counts['exemptions']} exemption entries")
|
|
174
|
+
if keywords_flag:
|
|
175
|
+
success_parts.append(f"{deleted_counts['keywords']} learned keywords")
|
|
176
|
+
|
|
177
|
+
success_message = "✅ Reset complete: Deleted " + ", ".join(success_parts)
|
|
178
|
+
self.stdout.write(self.style.SUCCESS(success_message))
|
|
179
|
+
|
|
180
|
+
if deleted_counts['errors']:
|
|
181
|
+
self.stdout.write(
|
|
182
|
+
self.style.WARNING(f"⚠️ Completed with {len(deleted_counts['errors'])} errors (see above)")
|
|
183
|
+
)
|