djust 0.2.1: WebSocket Security Hardening with Three Layers of Defense
Overview
djust 0.2.1 is a security-focused release that hardens the WebSocket event dispatch layer. Every LiveView that accepts user events over WebSocket is now protected by three layers of defense, all enabled by default in strict mode.
If you're running 0.2.0, upgrading requires one change: add @event_handler to your handler methods.
The Problem
In 0.2.0, any public method on a LiveView could be called from the client via WebSocket. A malicious client could dispatch events like __init__, _private_method, or any other method name, and getattr() would resolve it. This is a class of vulnerability common in RPC-style frameworks.
Three Layers of Defense
Layer 1: Event Name Guard
Before getattr() is ever called, event names are validated against a strict regex pattern:
^[a-z][a-z0-9_]*$
This blocks dunders (__init__), private methods (_secret), and any malformed names. Fast, cheap, and catches the obvious attacks.
Layer 2: @event_handler Allowlist
Only methods explicitly decorated with @event_handler can be called via WebSocket:
from djust import LiveView, event_handler
class CounterView(LiveView):
template_name = "counter.html"
def mount(self, request):
self.count = 0
@event_handler
def increment(self):
self.count += 1
@event_handler
def decrement(self):
self.count -= 1
def _internal_helper(self):
# Not callable from client - no decorator
pass
The security mode is configurable via LIVEVIEW_CONFIG:
"strict"(default) — only@event_handlermethods are callable, undecorated calls raise an error"warn"— undecorated methods still work but log a deprecation warning (use for gradual migration)"open"— no allowlist check (not recommended for production)
# settings.py
LIVEVIEW_CONFIG = {
"event_security": "strict", # default
}
Layer 3: Server-Side Rate Limiting
A token bucket algorithm limits event throughput per connection. Expensive handlers can set tighter limits with @rate_limit:
from djust import LiveView, event_handler, rate_limit
class SearchView(LiveView):
template_name = "search.html"
@event_handler
@rate_limit(rate=2, burst=5) # 2 per second, burst of 5
def search(self, query):
self.results = Product.objects.filter(name__icontains=query)[:20]
Connections that exceed the rate limit are disconnected with WebSocket close code 4429. After disconnection, a reconnection cooldown (default 5 seconds) prevents rapid reconnect loops.
Per-IP Connection Limits
A process-level IPConnectionTracker enforces a maximum number of concurrent WebSocket connections per IP address (default: 10). This prevents a single client from opening hundreds of connections to exhaust server resources.
# settings.py
LIVEVIEW_CONFIG = {
"rate_limit": {
"max_connections_per_ip": 10, # default
"reconnect_cooldown": 5, # seconds after rate-limit disconnect
},
"max_message_size": 65536, # 64KB default
}
The tracker supports X-Forwarded-For headers for deployments behind a reverse proxy.
New APIs
@event_handler— marks a method as callable via WebSocketis_event_handler(func)— check if a function is decorated@rate_limit(rate, burst)— per-handler rate limiting_allowed_eventsclass attribute — bulk allowlisting escape hatch for views with many handlers
Upgrading from 0.2.0
- Install the update:
pip install --upgrade djust==0.2.1 - Add
@event_handlerto every method that handles client events:from djust import event_handler # Add this decorator to all your handler methods @event_handler def my_handler(self, ...): ... - Optionally, start in
"warn"mode to find undecorated handlers without breaking anything:
Then switch toLIVEVIEW_CONFIG = {"event_security": "warn"}"strict"once all handlers are decorated.
What's Next
With the event dispatch layer secured, the next release will focus on new features. Follow the project on GitHub for updates.
Related Posts
djust 0.2.2: The Debug Panel Gets Real
djust 0.2.2 transforms the debug panel from a static inspector into a live development companion. Event filtering, replay, network inspection, VDOM patch tracing, and live state updates via WebSocket — all wired up and working out of the box.
djust 0.2.0: Template Operators, VDOM Fixes, and a Cleaner Event Syntax
djust 0.2.0 ships template and/or/in operators, critical VDOM diffing and whitespace fixes, a new dj- event prefix, and major dependency upgrades. Here's what changed and how to upgrade.
Introducing djust: Reactive Django Apps Powered by Rust
djust is a Django framework for building reactive, real-time applications in pure Python — powered by a Rust VDOM engine with 30x faster rendering than Django templates. No JavaScript framework required.