A Django app for security monitoring and SIEM integration
Project description
๐ก๏ธ django-security-monitor
A plug-and-play SIEM (Security Information & Event Management) library for Django. Monitor threats, detect attacks, score IPs, and visualize everything in a beautiful dark-mode dashboard โ all from inside your Django project.
๐ Table of Contents
- Features
- Screenshots
- Requirements
- Installation
- Quick Start
- Configuration
- Dashboard & URLs
- How Threat Scoring Works
- Redis Support
- Celery Support
- GeoIP Setup
- Models Reference
- Middleware Reference
- Security Settings Reference
- Management Commands
- Deployment Security
- FAQ
- License
โจ Features
| Category | Feature |
|---|---|
| ๐ Detection | SQL Injection, XSS, Path Traversal, Scanner User-Agents |
| ๐ชค Honeypot | Configurable trap URLs โ only bots/scanners trigger them |
| ๐ Auth | Brute-force login detection with per-IP failure counting |
| ๐ Scoring | Per-IP threat score with sigmoid hack-probability (0โ100%) |
| ๐ Blocking | Manual block/unblock + optional auto-block by threshold |
| โ Whitelist | Trusted IPs skip all detection |
| ๐ GeoIP | City-level geolocation via MaxMind GeoLite2 (optional) |
| ๐ Dashboard | Dark-mode SIEM UI with live feed, charts, IP drilldown |
| โก Redis | Rate-limiting via Redis cache when available (auto-detected) |
| ๐ฟ Celery | Score decay, event cleanup, email alerts (auto-detected) |
| ๐งฉ Configurable | All thresholds, paths, and weights set in settings.py |
๐ธ Screenshots
Dashboard ยท Events Log ยท Threat IPs ยท IP Detail
๐ฆ Requirements
- Python 3.9+
- Django 4.0+
geoip2(optional โ for geolocation)redis/django-redis(optional โ for fast rate limiting)celery(optional โ for background tasks)
๐ง Installation
######################################################################
1. Copy the app into your project
Using pip
pip install django-security-monitor
OR Using git
git clone https://github.com/ziadfox88/django_security_monitor.git
# Clone or download, then copy the folder
cp -r django_security_monitor/ /your/project/
##########################################################################
2. Install dependencies
# Required
pip install django
# Optional but recommended
pip install geoip2 # geolocation
pip install django-redis # Redis rate limiting
pip install celery # background tasks
###############################################################
3. Add to INSTALLED_APPS
# settings.py
INSTALLED_APPS = [
...
'django_security_monitor',
]
##################################################################
4. Add middleware
# settings.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django_security_monitor.middleware.SecurityMonitorMiddleware', # โ before sessions
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django_security_monitor.middleware.VisitorTrackingMiddleware', # โ after auth
...
]
#############################################################################
5. Add URLs
# urls.py (main project)
from django.urls import path, include
urlpatterns = [
...
path('security-monitor/', include('django_security_monitor.urls')),
]
####################################################################################
6. Run migrations
python manage.py makemigrations django_security_monitor
python manage.py migrate
#######################################################################################
7. Visit the dashboard
http://yoursite.com/security-monitor/
### NOTE
โ ๏ธ Only superusers can access the dashboard by default.
###############################################################################
โก Quick Start
Minimal settings.py addition to get running immediately:
SECURITY_MONITOR = {
'BLOCK_THRESHOLD': 50,
'AUTO_BLOCK': False,
'ALERT_EMAIL': 'admin@yoursite.com',
}
That's it. Detection, scoring, and the dashboard are active.
#######################################################################
โ๏ธ Configuration
All configuration lives under the SECURITY_MONITOR dict in your settings.py.
Every key is optional โ defaults are used for anything you omit.
SECURITY_MONITOR = {
# โโ Access Control โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# List of usernames who can access the dashboard.
# Leave empty to allow superusers only.
'ALLOWED_USERS': [],
# โโ Threat Detection โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# URL fragments that trigger a "suspicious path" event.
'SUSPICIOUS_PATHS': [
'.env', '.git', '.svn', 'wp-admin', 'wp-login',
'phpMyAdmin', '/etc/passwd', '/etc/shadow',
'.htaccess', '.htpasswd', 'web.config', '.DS_Store',
'xmlrpc.php', '/proc/', 'backup.sql',
],
# File extensions that trigger a "sensitive file" event.
'SENSITIVE_EXTENSIONS': [
'.env', '.sql', '.bak', '.backup', '.dump',
'.config', '.conf', '.key', '.pem',
'.p12', '.pfx', '.log', '.db', '.sqlite3',
],
# URLs that act as traps. Any access = instant high threat score.
# Real users never visit these; only bots/scanners do.
'HONEYPOT_PATHS': [
'/wp-login.php', '/wp-admin/', '/.env',
'/.git/config', '/phpinfo.php', '/shell.php',
'/c99.php', '/r57.php', '/admin.php',
],
# โโ Auto-Blocking โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Set to False to track threats without ever auto-blocking.
'AUTO_BLOCK': True,
# Threat score at which an IP is automatically blocked.
'BLOCK_THRESHOLD': 50,
# โโ Rate Limiting โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Max requests from one IP within RATE_LIMIT_WINDOW seconds.
'RATE_LIMIT': 200,
'RATE_LIMIT_WINDOW': 60,
# โโ Brute Force Detection โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Failed logins before escalating to "brute_force" event.
'MAX_LOGIN_ATTEMPTS': 5,
'LOGIN_ATTEMPT_WINDOW': 300, # 5 minutes
# โโ Optional Integrations โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# None = auto-detect from your CACHES / installed packages
# True = force enable (raises error if not installed)
# False = force disable
'USE_REDIS': None,
'USE_CELERY': None,
# โโ Logging โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
'LOG_404': True, # Log 404 responses as low-severity events
'LOG_500': True, # Log 500 responses as low-severity events
# How many days to keep events before cleanup (Celery required)
'EVENT_RETENTION_DAYS': 90,
# Email address for critical-event alerts (Celery required)
'ALERT_EMAIL': None,
# โโ Paths โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Paths that are completely skipped by both middlewares.
'EXCLUDE_PATHS': ['/static/', '/media/'],
# Whitelist cache refresh interval (seconds)
'WHITELIST_CACHE_TTL': 300,
# URL or name to return to your main application dashboard.
# If set, a "Project Dashboard" link appears in the sidebar.
'BACK_URL': 'home',
# โโ Scoring Weights โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# How many threat score points each event type adds.
'THREAT_SCORE_WEIGHTS': {
'suspicious_path': 15,
'sensitive_file': 20,
'rate_limit': 10,
'auth_failure': 5,
'brute_force': 25,
'sql_injection': 30,
'xss_attempt': 25,
'path_traversal': 35,
'scanner': 20,
'honeypot': 40,
'404': 3,
'500': 2,
'csrf_failure': 15,
},
}
######################################################################
๐ฅ๏ธ Dashboard & URLs
URL View Description
/security-monitor/ Dashboard Overview, charts, live feed
/security-monitor/events/ Events Log Filterable security event list
/security-monitor/threats/ Threat IPs IP scores with hack probability
/security-monitor/threats/<ip>/ IP Detail Full drilldown for one IP
/security-monitor/visitors/ Visitors All tracked visitors
/security-monitor/block/<ip>/ POST Block an IP
/security-monitor/unblock/<ip>/ POST Unblock an IP
/security-monitor/whitelist/<ip>/ POST Whitelist (trust) an IP
/security-monitor/api/live-events/ JSON Real-time event feed
/security-monitor/api/stats/ JSON Live stat card data
########################################################################
Changing the dashboard URL prefix
# urls.py
path('my-custom-path/', include('django_security_monitor.urls')),
###########################################################################
Granting non-superuser access
SECURITY_MONITOR = {
'ALLOWED_USERS': ['alice', 'security_team_member'],
}
#############################################################################
๐งฎ How Threat Scoring Works
Every suspicious action from an IP adds points to its Threat Score.
The score is converted to a Hack Probability (0โ100%) using a sigmoid curve:
Probability = 100 / (1 + e^(-0.08 ร (score - 40)))
############################################################################
Risk Levels
Score Risk Level Hack Probability
0โ19 ๐ข Low ~5%
20โ49 ๐ก Medium ~18โ45%
50โ79 ๐ High ~50โ83%
80+ ๐ด Critical ~84โ99%
###########################################################################
Score Examples
IP hits /.env โ +40 (honeypot)
IP sends SQL injection payload โ +30
IP fails login 5 times โ +25 (brute_force escalation)
IP scans 200+ paths in 60s โ +10 (rate limit)
Total: 105 โ Probability: ~98% โ Auto-blocked โ
###########################################################################
Score Decay (Celery required)
Scores automatically decay by 10% every hour for non-blocked IPs,
so old benign misses don't permanently flag legitimate users.
###############################################################################
โก Redis Support
When your project uses Redis as the Django cache backend,
django-security-monitor automatically uses it for fast, atomic rate limiting.
# settings.py โ example Redis cache setup
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/1',
}
}
If Redis is not configured, rate limiting falls back to database
counting automatically โ no configuration needed.
To force-disable Redis even if it's available:
SECURITY_MONITOR = {
'USE_REDIS': False,
}
########################################################################################
๐ฟ Celery Support
When Celery is installed and configured, three periodic tasks become available:
Task Schedule Description
security_monitor.cleanup_old_events Daily 3am Delete events older than EVENT_RETENTION_DAYS
security_monitor.decay_threat_scores Every hour Reduce scores by 10% for inactive IPs
security_monitor.send_critical_alert On trigger Email admin on critical event
Register the beat schedule:
# settings.py
from celery.schedules import crontab
CELERY_BEAT_SCHEDULE = {
'siem-cleanup': {
'task': 'security_monitor.cleanup_old_events',
'schedule': crontab(hour=3, minute=0),
},
'siem-decay': {
'task': 'security_monitor.decay_threat_scores',
'schedule': crontab(minute=0),
},
}
If Celery is not installed, all tasks are silently skipped โ nothing breaks.
########################################################################################
๐ GeoIP Setup
Geolocation enriches visitor and threat records with country, city, and coordinates.
1. Get the free MaxMind GeoLite2 database
Register at maxmind.com
and download GeoLite2-City.mmdb.
2. Place the file
your_project/
โโโ geoip/
โโโ GeoLite2-City.mmdb โ here
3. Configure the path
# settings.py
GEOIP_PATH = BASE_DIR / 'geoip'
If the file is missing, geolocation is silently skipped โ the app
still works fully without it.
##############################################################################################
๐๏ธ Models Reference
SecurityEvent
Logs every detected threat or suspicious action.
| Field | Type | Description |
| ------------------ | ------------- | ------------------------------------- |
| ip_address | CharField | Source IP |
| event_type | CharField | One of 15 event types |
| severity | CharField | info / low / medium / high / critical |
| path | CharField | Requested path |
| method | CharField | HTTP method |
| user_agent | CharField | Browser/bot UA string |
| payload | TextField | Captured suspicious payload |
| threat_score_delta | FloatField | Points added by this event |
| timestamp | DateTimeField | When it happened |
############################################################################################
ThreatScore
Aggregated per-IP threat intelligence.
| Field | Type | Description |
| ---------------- | ------------ | ------------------------------- |
| ip_address | CharField | Unique IP |
| score | FloatField | Cumulative threat score |
| hack_probability | property | 0โ100% sigmoid probability |
| risk_level | property | low / medium / high / critical |
| is_blocked | BooleanField | Whether IP is currently blocked |
| block_reason | CharField | Why it was blocked |
| location | JSONField | GeoIP data |
###############################################################################
LoginAttempt
Raw log of every login success and failure.
| Field | Type | Description |
| ---------- | ------------- | ----------------------- |
| ip_address | CharField | Source IP |
| username | CharField | Attempted username |
| success | BooleanField | Whether login succeeded |
| timestamp | DateTimeField | When it happened |
############################################################################
HoneypotHit
Every access to a configured honeypot URL.
| Field | Type | Description |
| ---------- | ------------- | ---------------------- |
| ip_address | CharField | Source IP |
| path | CharField | Honeypot path accessed |
| headers | JSONField | Full request headers |
| timestamp | DateTimeField | When it happened |
########################################################################
IPWhitelist
Trusted IPs that bypass all detection.
| Field | Type | Description |
| ---------- | ---------- | ----------------------- |
| ip_address | CharField | Trusted IP |
| added_by | ForeignKey | Admin user who added it |
| reason | CharField | Why it's trusted |
########################################################################
Visitor
Session-based visitor tracking.
| Field | Type | Description |
| ----------- | -------------------- | ----------------------------- |
| session_key | CharField | Django session key |
| ip_address | CharField | Visitor IP |
| visit_count | PositiveIntegerField | Total visits |
| location | JSONField | GeoIP enrichment |
| user | ForeignKey | Linked auth user if logged in |
########################################################################
๐ Middleware Reference
SecurityMonitorMiddleware
Place before SessionMiddleware. Runs security analysis on every request.
Detects:
SQL Injection in query strings
XSS patterns in query strings
Path traversal sequences (../, %2e%2e%2f, etc.)
Scanner user-agents (Nikto, sqlmap, Nmap, Burp Suite, etc.)
Suspicious and sensitive paths
Honeypot accesses
Rate limit violations
Blocked IP re-entry attempts
VisitorTrackingMiddleware
Place after AuthenticationMiddleware. Tracks every unique session.
Records:
Session โ IP โ User linkage
Visit counts and timestamps
GeoIP location on first visit
Per-request page views with response time and status code
########################################################################
SECURITY_MONITOR = {
# Who can see the dashboard
'ALLOWED_USERS': [], # [] = superuser only
# Blocking
'AUTO_BLOCK': False, # False = monitor only, never block
'BLOCK_THRESHOLD': 50, # score needed for auto-block
# Rate limiting (per IP)
'RATE_LIMIT': 200, # requests allowed
'RATE_LIMIT_WINDOW': 60, # per this many seconds
# Brute force
'MAX_LOGIN_ATTEMPTS': 5, # failures before brute_force event
'LOGIN_ATTEMPT_WINDOW': 300, # within this window (seconds)
# Return link
'BACK_URL': '/dashboard/',
}
Predicted Latency Per Request
Every request passes through two middleware layers. Here is what each one costs:
SecurityMonitorMiddleware:
| Operation | Type | Cost |
| ------------------------------------------ | -------------- | ---------- |
| Path/exclude checks | In-memory | ~0.01ms |
| Whitelist set lookup | In-memory | ~0.01ms |
| Regex pattern matching (SQL/XSS/traversal) | In-memory | ~0.1โ0.3ms |
| Rate limit check (Redis) | Redis GET+INCR | ~0.2โ0.5ms |
| Rate limit check (DB fallback) | DB COUNT query | ~1โ3ms |
| SecurityEvent INSERT (if attack detected) | DB write | ~2โ5ms |
| ThreatScore UPDATE (if attack detected) | DB write | ~2โ4ms |
Normal clean request (no attack detected):
With Redis โ ~0.5โ1ms overhead
Without Redis โ ~2โ4ms overhead
Attack detected (writes happen):
With Redis โ ~3โ6ms overhead
Without Redis โ ~5โ12ms overhead
VisitorTrackingMiddleware:
| Operation | Type | Cost |
| --------------------- | ------------- | ------- |
| Session check | In-memory | ~0.01ms |
| Visitor GET_OR_CREATE | DB read+write | ~1โ3ms |
| Visit count UPDATE | DB write | ~1โ2ms |
| PageView INSERT | DB write | ~1โ3ms |
Every request: ~3โ8ms overhead (this runs on every single request)
Total Expected Overhead
| Scenario | With Redis | Without Redis |
| ------------------------------------ | ---------- | ------------- |
| Clean request, existing visitor | ~3.5โ5ms | ~5โ10ms |
| Clean request, new visitor (+ GeoIP) | ~5โ8ms | ~7โ14ms |
| Attack detected | ~7โ14ms | ~10โ22ms |
For reference โ a typical Django view with one DB query already costs 10โ50ms. So on a clean request, the library adds roughly 10โ30% overhead without Redis, and 5โ15% with Redis
Will It Make the App Heavy?
Short answer: No โ if you follow these rules:
โ
What makes it lightweight
All regex checks are compiled once at startup, not per-request
โ
The whitelist is cached in memory and only refreshed every 5 minutes
EXCLUDE_PATHS skips /static/ and /media/ entirely โ those are usually 60โ80% of all requests
With Redis, rate limiting never touches the DB
โ ๏ธ What can make it heavy
PageView writes every request โ this is the biggest cost at scale
Without Redis, the DB COUNT for rate limiting runs on every request
GeoIP lookup runs on first visit (disk read) but is negligible after that
At high traffic without Celery, the SecurityEvent table grows fast
########################################################################
๐ก๏ธ Deployment Security
To ensure maximum security when using this library in production:
### 1. Trusted Proxies & IP Spoofing
The library uses `X-Forwarded-For` and `X-Real-IP` headers to identify visitors. If your app is not behind a trusted proxy (like Nginx, Gunicorn, or Cloudflare) that strips these headers from the client, an attacker can spoof their IP address.
**Recommendation:** Always ensure your web server is configured to set these headers correctly and ignore client-supplied values.
### 2. Database Growth
In high-traffic sites, the `SecurityEvent` and `PageView` tables can grow rapidly.
**Recommendation:** Enable Celery to use the automatic cleanup tasks, or manually run a cron job to prune old records.
### 3. Dashboard Access
By default, the dashboard is only accessible to superusers. If you use `ALLOWED_USERS`, ensure you only list trusted usernames.
**Recommendation:** Use a strong password policy and MFA for any account that has access to the security dashboard.
########################################################################
โ FAQ
Q: Does this replace Django's built-in security middleware?
No. It works alongside django.middleware.security.SecurityMiddleware.
Place Django's security middleware first, then this one.
Q: Will it slow down my site?
Minimal impact. DB writes are fast single-row operations.
With Redis enabled, rate limiting is in-memory with zero DB queries.
The EXCLUDE_PATHS setting lets you skip static/media entirely.
Q: What if I don't have GeoIP?
Everything works normally. IP location fields will simply be empty.
Q: Can I use this with a custom user model?
Yes. All user foreign keys use settings.AUTH_USER_MODEL.
Q: How do I stop a legitimate IP from being scored?
Add it to the whitelist via the dashboard or Django admin.
Whitelisted IPs skip all middleware checks entirely.
Q: Can I add my own event types?
Yes โ call SecurityEvent.objects.create(...) directly from anywhere
in your code with any event_type string you choose.
########################################################################
๐ License
MIT License โ free to use, modify, and distribute.
##################################################################
๐ค Author
Built by Ziad Ali
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_security_monitor-0.1.5.tar.gz.
File metadata
- Download URL: django_security_monitor-0.1.5.tar.gz
- Upload date:
- Size: 38.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b95e0c6281b2ce46a0aecc845bee7568e147b651c804c47dd0bbd08f9d790d3c
|
|
| MD5 |
b8ad94a843a1057ceeb1a0cf274f69fb
|
|
| BLAKE2b-256 |
18ae687016df8854be13e72d3b53662bb1fd267c8272eeff973758f0cfc539ef
|
Provenance
The following attestation bundles were made for django_security_monitor-0.1.5.tar.gz:
Publisher:
publish.yml on ziadfox88/django_security_monitor
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_security_monitor-0.1.5.tar.gz -
Subject digest:
b95e0c6281b2ce46a0aecc845bee7568e147b651c804c47dd0bbd08f9d790d3c - Sigstore transparency entry: 1183141220
- Sigstore integration time:
-
Permalink:
ziadfox88/django_security_monitor@ef45fede7b0466137db267b60ace65ff6805fb2c -
Branch / Tag:
refs/tags/v0.1.5 - Owner: https://github.com/ziadfox88
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ef45fede7b0466137db267b60ace65ff6805fb2c -
Trigger Event:
push
-
Statement type:
File details
Details for the file django_security_monitor-0.1.5-py3-none-any.whl.
File metadata
- Download URL: django_security_monitor-0.1.5-py3-none-any.whl
- Upload date:
- Size: 49.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
15e8a94118394051e9341d58122cf916597ae1bdcb83be2c22a58552f7812641
|
|
| MD5 |
a82a20a20fa18c508a331fe2ed33122d
|
|
| BLAKE2b-256 |
4a8458b5d98b336b00b5c23608065f20d3cb262727b0512596c64ce8ad7fce8d
|
Provenance
The following attestation bundles were made for django_security_monitor-0.1.5-py3-none-any.whl:
Publisher:
publish.yml on ziadfox88/django_security_monitor
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_security_monitor-0.1.5-py3-none-any.whl -
Subject digest:
15e8a94118394051e9341d58122cf916597ae1bdcb83be2c22a58552f7812641 - Sigstore transparency entry: 1183141247
- Sigstore integration time:
-
Permalink:
ziadfox88/django_security_monitor@ef45fede7b0466137db267b60ace65ff6805fb2c -
Branch / Tag:
refs/tags/v0.1.5 - Owner: https://github.com/ziadfox88
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ef45fede7b0466137db267b60ace65ff6805fb2c -
Trigger Event:
push
-
Statement type: