Django
Add Nyoxis threat detection to a Django application as a MIDDLEWARE class.
Prerequisites
- Python 3.9 or later
- Django 3.2 or later
- A Nyoxis workspace API key — get one here
Install
bash
pip install requestsMiddleware class
Create nyoxis/middleware.py inside your Django project (or any installed app):
python
from __future__ import annotations
import logging
import os
from typing import Any
import requests
from django.http import JsonResponse
NYO_API = "https://api.nyoxis.com"
logger = logging.getLogger("nyoxis")
class NyoxisWAFMiddleware:
"""
Django MIDDLEWARE that calls /v0/predict for every inbound request.
Settings (in settings.py):
NYOXIS_API_KEY (str) required — your workspace token
NYOXIS_BLOCK_ON_HIGH (bool) default False
NYOXIS_ON_ERROR (str) "open" (default) | "closed"
"""
def __init__(self, get_response):
from django.conf import settings
self.get_response = get_response
self.api_key = getattr(settings, "NYOXIS_API_KEY", os.environ.get("NYOXIS_API_KEY"))
self.block_on_high = getattr(settings, "NYOXIS_BLOCK_ON_HIGH", False)
self.on_error = getattr(settings, "NYOXIS_ON_ERROR", "open")
if not self.api_key:
raise RuntimeError("Nyoxis: NYOXIS_API_KEY is not configured")
def __call__(self, request):
payload: dict[str, Any] = {
"method": request.method,
"path": request.path,
"query": request.META.get("QUERY_STRING") or None,
"ip_addr": self._get_client_ip(request),
"headers": {k: v for k, v in request.headers.items()},
"body": request.body.decode("utf-8", errors="replace") or None,
}
try:
resp = requests.post(
f"{NYO_API}/v0/predict",
params={"api_key": self.api_key},
json=payload,
timeout=3,
)
verdict = resp.json()
# Attach to the request object for view access
request.nyoxis = verdict
if self.block_on_high:
risk = (verdict.get("prediction") or {}).get("risk")
if risk == "high":
return JsonResponse({"error": "Forbidden"}, status=403)
except Exception as exc:
logger.warning("nyoxis: prediction error: %s", exc)
if self.on_error == "closed":
return JsonResponse({"error": "Service unavailable"}, status=503)
return self.get_response(request)
@staticmethod
def _get_client_ip(request) -> str | None:
forwarded = request.META.get("HTTP_X_FORWARDED_FOR")
if forwarded:
return forwarded.split(",")[0].strip()
return request.META.get("REMOTE_ADDR")Register in settings.py
Add the middleware near the top of MIDDLEWARE, after SecurityMiddleware:
python
# settings.py
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"nyoxis.middleware.NyoxisWAFMiddleware", # ← add here
"django.contrib.sessions.middleware.SessionMiddleware",
# ...
]
NYOXIS_API_KEY = os.environ["NYOXIS_API_KEY"]
NYOXIS_BLOCK_ON_HIGH = TrueActing on the verdict
The verdict is available as request.nyoxis in any view:
python
from django.http import HttpRequest, JsonResponse, HttpResponseForbidden
def sensitive_view(request: HttpRequest):
verdict = getattr(request, "nyoxis", {})
prediction = verdict.get("prediction") or {}
risk = prediction.get("risk", "none")
if risk in ("medium", "high"):
return HttpResponseForbidden("Forbidden")
attacks = prediction.get("attacks", [])
if any(a["kind"] == "xss" for a in attacks):
# Log and continue — don't hard-block on a single signal
import logging
logging.getLogger("security").warning(
"XSS signal on %s from %s",
request.path,
request.META.get("REMOTE_ADDR"),
)
return JsonResponse({"data": "sensitive content"})Async views
For Django 4.1+ async views, use httpx instead of requests and make __call__ async:
python
import httpx
class NyoxisWAFMiddlewareAsync:
async def __call__(self, request):
payload = {"method": request.method, "path": request.path}
async with httpx.AsyncClient(timeout=3) as client:
try:
resp = await client.post(
f"{NYO_API}/v0/predict",
params={"api_key": self.api_key},
json=payload,
)
request.nyoxis = resp.json()
except Exception as exc:
logger.warning("nyoxis error: %s", exc)
return await self.get_response(request)Next steps
- API Reference — complete field descriptions and status codes.
- Overview — how the classifier and redaction pipeline work.