Django Setup
Source and package versions
One AIWAF repository.
Python: py/aiwaf/ · Node.js: js/ · Rust/WASM: rust/ · Java: java/.
Source and canonical README.
Versions shown describe the source checkout; package releases are independent.
Current Python/Node source targets are aiwaf 1.1.8 (Python) and
aiwaf 1.1.5 (npm), with Rust/Python 0.2.7 and
WASM 0.2.5 and Java 1.3.5. Sandbox guides retain their separately pinned builds.
Release candidate: this page documents Python 1.1.8 and Rust/Python 0.2.7 in the current source checkout. Source versions do not establish registry availability. Python 1.1.8 requires aiwaf-rust>=0.2.7; framework dependencies remain extras.
This guide retains the legacy integration steps. Use the native adapter example for the Rust-owned CSV pipeline.
How AIWAF works: system architecture
Add AIWAF to a Django application and verify that protection is registered with the live route table.
Use an environment compatible with your framework. This guide assumes an existing Django project with manage.py and a settings module. New to middleware? Start with the six-step first protected app tutorial, which includes complete files and expected responses.
1. Install the framework extra
pip install "aiwaf[django]"
# Python 1.1.4 installs its required Rust runtime automatically.
Install into the environment used to run your application. Choose an interpreter compatible with the framework and dependencies.
2. Register protection
project/settings.py (merge into existing lists)
Add the app and the unified middleware alias in settings.py:
INSTALLED_APPS = [
# ...
"aiwaf.django",
]
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"aiwaf.django.middleware.all",
# ...
]
For explicit ordering, replace the alias with the individual middleware classes:
MIDDLEWARE = [
"aiwaf.django.middleware.JsonExceptionMiddleware",
"aiwaf.django.middleware.GeoBlockMiddleware",
"aiwaf.django.middleware.IPAndKeywordBlockMiddleware",
"aiwaf.django.middleware.RateLimitMiddleware",
"aiwaf.django.middleware.AIAnomalyMiddleware",
"aiwaf.django.middleware.HoneypotTimingMiddleware",
"aiwaf.django.middleware.UUIDTamperMiddleware",
"aiwaf.django.middleware.HeaderValidationMiddleware",
"aiwaf.django.middleware_logger.AIWAFLoggerMiddleware",
]
Protection middleware should run early. Logging should run late enough to observe the application response.
3. Discover your live routes
Run from the application checkout after all routes are registered:
aiwaf init --framework django --settings project.settings
The default output is .aiwaf/paths.json. Flask and FastAPI require module:object in --app; Flask factories such as app:create_app are supported. Repeat discovery when registered routes change.
4. Scope route exemptions
project/views.py
from django.http import JsonResponse
from aiwaf.django import aiwaf_exempt, aiwaf_only
@aiwaf_exempt
def health(request):
return JsonResponse({"ok": True})
@aiwaf_only("header_validation")
def webhook(request):
return JsonResponse({"accepted": True})
Merge these paths into your existing Django URL configuration, keeping other project routes:
project/urls.py
from django.urls import path
from .views import health, webhook
urlpatterns = [
path("health/", health),
path("webhook/", webhook),
# Keep your existing paths here.
]Apply migrations for ORM-backed stores:
python manage.py makemigrations aiwaf
python manage.py migrate
python manage.py check
5. Configure settings and model storage
Define flat AIWAF_* settings in your Django settings module. Merge the app and middleware into existing lists rather than replacing your authentication/session middleware.
| Area | Important settings |
|---|---|
| Training | AIWAF_ACCESS_LOG, AIWAF_MIN_TRAIN_LOGS, AIWAF_MIN_AI_LOGS, AIWAF_FORCE_AI_TRAINING |
| Rate limiting | AIWAF_RATE_WINDOW, AIWAF_RATE_MAX, AIWAF_RATE_FLOOD |
| Headers | AIWAF_REQUIRED_HEADERS, AIWAF_HEADER_QUALITY_MIN_SCORE |
| Honeypot | AIWAF_MIN_FORM_TIME, AIWAF_MAX_PAGE_TIME |
| UUID checks | AIWAF_UUID_SCORE_ENABLED, AIWAF_UUID_SCORE_BLOCK_THRESHOLD |
| GeoIP | AIWAF_GEO_BLOCK_ENABLED, AIWAF_GEO_BLOCK_COUNTRIES, AIWAF_GEO_ALLOW_COUNTRIES |
| Exemptions | AIWAF_EXEMPT_PATHS, AIWAF_EXEMPT_KEYWORDS, AIWAF_ALLOWED_PATH_KEYWORDS |
| Models | AIWAF_MODEL_PATH, AIWAF_MODEL_STORAGE, AIWAF_MODEL_STORAGE_FALLBACK |
When aiwaf_rust is importable, supported acceleration paths are selected automatically. Python remains the fallback when a native capability is unavailable. Persisted runtime models use JSON state; AIWAF does not load pickle, joblib, or other executable Python-object formats.
6. Check and run Django
python manage.py check
python manage.py migrate
python manage.py runserverThe settings snippet does not create an application view. Request http://127.0.0.1:8000/health/ after registering the health view as shown above. It should return {"ok": true}. Then test a non-exempt application route for normal and rejected traffic; health is deliberately exempt.
python manage.py detect_and_train --help
python manage.py regenerate_model --helpUse Python operations for training, model inspection, and state migration. Training requires representative logs in a supported format; setup alone does not train a model.
Production configuration
- Configure the application to trust forwarding headers only from known proxy CIDRs.
- Configure the outermost proxy to overwrite client-supplied forwarding headers.
- Use Redis, a database, or another shared backend when multiple workers must share rate-limit, blocklist, or exemption state.
- Keep health checks, static assets, and trusted webhook routes explicitly scoped instead of disabling protection globally.
- Start anomaly detection in observe-only or conservative mode and tune it with representative normal traffic.
- Rotate logs and exclude secrets, authorization headers, cookies, and personal data.
- Sign model/configuration artifacts where the runtime supports HMAC verification.
- Run AIWAF alongside normal secure-development controls and an edge/reverse-proxy layer.
Rust-owned CSV request pipeline
Release candidate: this page documents Python 1.1.8 and Rust/Python 0.2.7 in the current source checkout. Source versions do not establish registry availability. Python 1.1.8 requires aiwaf-rust>=0.2.7; framework dependencies remain extras.
Install the explicit native adapter instead of the existing AIWAF middleware chain. Installing the required Rust dependency does not automatically switch existing applications to this pipeline. Legacy adapters remain available for custom stores and hooks; their configuration and fallback behavior are separate.
# settings.py: retain the other middleware required by your app.
AIWAF_CSV_PIPELINE = {"data_dir": "aiwaf_data"}
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"aiwaf.django.csv_pipeline.NativeAIWAFMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]The earlier setup steps on this page describe the legacy adapter. For native mode, replace that initialization with the example here and configure the dedicated lowercase profile. Do not install both chains. Keep Django session/authentication middleware before the native adapter.
Rust owns the native CSV pipeline configuration, enforcement order, SQL and keyword inspection, geo/blocklist decisions, rate buckets, form timing, UUID scores, anomaly history/inference, keyword learning, and CSV logging. Python supplies framework routes, authentication facts, GeoIP lookup, bounded request buffering, and response construction. Training and management still have Python interfaces.
Continue with the request lifecycle, the native profile, migration, and performance and deployment.
Shared Python CSV storage
List APIs and command help now use blocklist and allowlist. Earlier import/method/command spellings remain compatibility aliases. Existing CSV filenames and Django model identity are retained so upgrades preserve stored blocks and exemptions; use the package storage constants rather than constructing filenames.
Python 1.1.4 standardizes Flask, FastAPI, Django CSV mode, and the explicit native pipeline on blacklist.csv, whitelist.csv, keywords.csv, geo_blocked_countries.csv, and path_exemptions.csv. Keyword frequencies and non-policy runtime history are retained in runtime_metadata.csv. Memory, JSON-file, database, and Django ORM modes keep their existing storage behavior.
| Integration | CSV directory configuration |
|---|---|
| Legacy Flask | Set app.config['AIWAF_USE_CSV'] = True and app.config['AIWAF_DATA_DIR'] before initializing AIWAF. |
| Legacy Django | Set AIWAF_STORAGE_MODE = "csv" and AIWAF_DATA_DIR in project settings. |
| Legacy FastAPI | Pass storage={"backend": "csv", "data_dir": "/absolute/path/aiwaf_data"} to AIWAF. Its default backend remains memory. |
| Native adapters | Pass the lowercase data_dir in the dedicated native profile. Native adapters do not inherit legacy framework settings. |
Startup imports legacy runtime CSV data once, preserving block expiry and metadata. Original sources remain intact; backups and completion markers support recovery and prevent removed entries from returning on restart. Existing canonical policy wins conflicts. Stop old workers before upgrading and use the same absolute directory for the application and CLI. See migration paths and recovery.
Flask management searches existing project aiwaf_data and .aiwaf/data before user/package directories. Explicit AIWAF_DATA_DIR or --data-dir takes priority. The five policy files use UTF-8 across Python and Rust. Sharing these files does not make memory rate buckets, model history, or optional memory form timing distributed.
Flask and FastAPI native honeypot cache
Python 1.1.8 with aiwaf-rust 0.2.7 adds opt-in Redis and supplied-cache timing to both native adapters. CSV remains their default. Rust retains timing rules and exemptions; only timestamp I/O uses the cache.
import os
profile = {
"data_dir": "aiwaf_data",
"honeypot_backend": "redis",
"honeypot_redis_url": os.environ["AIWAF_REDIS_URL"],
"honeypot_cache_namespace": "myapp:honeypot:v1",
}
# Flask:
from aiwaf.flask.csv_pipeline import NativeAIWAF
NativeAIWAF(app, config=profile)
# FastAPI alternative:
# from aiwaf.fast.csv_pipeline import NativeAIWAFMiddleware
# app.add_middleware(NativeAIWAFMiddleware, config=profile)
For Flask-Caching or a compatible custom object, use honeypot_backend="cache" and pass honeypot_cache=cache to the native adapter. It must provide synchronous get(key) and set(key, value, timeout=seconds), preserve the timestamp/expiry pair, honor TTL and propagate errors. A false write result means failure; silent/no-op backends are unsuitable. Local caches remain worker-local. Use a shared backend and the same namespace across workers; isolate unrelated applications with different namespaces.
Records have a 300-second TTL. Missing/evicted timestamps allow the timing check, while cache errors and invalid records return generic HTTP 503. Expired-page POSTs return 409 until a new GET or TTL expiry; old snapshots are not deleted. FastAPI runs cache-backed native checks in its worker thread pool so synchronous cache I/O does not block the event loop. Other policy stores and legacy middleware behavior are unchanged.
Django native honeypot cache
Python 1.1.8 with aiwaf-rust 0.2.7 defaults Django native honeypot timing to Django's configured cache. Set honeypot_cache_alias in AIWAF_CSV_PIPELINE to select an alias; it defaults to default. Rust calls a small Python cache adapter for timestamp I/O and retains timing decisions, logical expiry and exemptions. Other policy CSVs and rate-limit configuration are unchanged.
AIWAF_CSV_PIPELINE = {
"data_dir": "aiwaf_data",
"honeypot_cache_alias": "default",
}
# Configure CACHES["default"] with a shared backend for multiple workers.
Redis or Memcached can share timestamps across workers. LocMemCache is supported with a startup warning; it remains worker-local. DummyCache is rejected when honeypot protection is enabled. Cache errors, failed writes and invalid records produce generic HTTP 503; known ignored-cache-error modes are rejected.
Entries use a 300-second TTL. Expired-page POSTs return 409 until a new GET or TTL expiry. No eager deletion occurs, so an old POST cannot erase a concurrent refresh. A missing or evicted timestamp allows the POST timing check, as before; cache failure is not treated as a miss. Backends do not transfer existing timestamps. Install the matching Rust extension and restart workers together.
Explicit honeypot_backend="csv" retains filesystem timing; "memory" uses Rust's per-engine map. Flask, FastAPI and direct native construction keep CSV as the default. See the Django cache documentation.
Training replay protection
Python 1.1.6 with aiwaf-rust 0.2.5 uses Rust-owned receipts in Flask, FastAPI, and Django. Reusing requests already handled by training cannot extend or recreate a block. Fresh requests must independently satisfy enforcement rules; models and keyword learning can still reuse historical logs.
Keep training_evidence.json across expiry, manual unblocking, log rotation, and restarts. It lives in the policy data directory unless AIWAF_TRAINING_STATE_DIR selects another durable directory. Trainers sharing a blocklist must share that directory. Receipts start with this release and cannot reconstruct decisions made by older versions. Missing native support and corrupt state stop training visibly. Block and receipt writes are separate, so a crash between them can require recovery.
Flask CLI listing now filters expired entries without rewriting an older snapshot over blocks concurrently added or refreshed by a trainer. The CLI displays the canonical added_date, with the older timestamp as a fallback. This listing fix and training replay protection address different causes of block changes. A first temporary block defaults to 900 seconds; later reputation decisions can increase its duration. Check the stored expiry rather than assuming every block lasts 24 hours.
