mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 17:11:09 -05:00
339 lines
7.2 KiB
Markdown
339 lines
7.2 KiB
Markdown
# Security Documentation
|
|
|
|
## Authentication System
|
|
|
|
### Authentication Stack
|
|
```python
|
|
# Settings configuration
|
|
AUTHENTICATION_BACKENDS = [
|
|
'django.contrib.auth.backends.ModelBackend',
|
|
'allauth.account.auth_backends.AuthenticationBackend',
|
|
]
|
|
|
|
INSTALLED_APPS = [
|
|
'django.contrib.auth',
|
|
'django.contrib.sessions',
|
|
'allauth',
|
|
'allauth.account',
|
|
'allauth.socialaccount',
|
|
'oauth2_provider',
|
|
]
|
|
```
|
|
|
|
### Authentication Flow
|
|
```mermaid
|
|
sequenceDiagram
|
|
User->>+Server: Login Request
|
|
Server->>+Auth Service: Validate Credentials
|
|
Auth Service->>+Database: Check User
|
|
Database-->>-Auth Service: User Data
|
|
Auth Service-->>-Server: Auth Token
|
|
Server-->>-User: Session Cookie
|
|
```
|
|
|
|
## Authorization Framework
|
|
|
|
### Permission System
|
|
|
|
#### Model Permissions
|
|
```python
|
|
class Park(models.Model):
|
|
class Meta:
|
|
permissions = [
|
|
("can_publish_park", "Can publish park"),
|
|
("can_moderate_park", "Can moderate park"),
|
|
("can_verify_park", "Can verify park information"),
|
|
]
|
|
```
|
|
|
|
#### View Permissions
|
|
```python
|
|
class ModeratedCreateView(LoginRequiredMixin, PermissionRequiredMixin):
|
|
permission_required = 'parks.can_publish_park'
|
|
raise_exception = True
|
|
```
|
|
|
|
### Role-Based Access Control
|
|
|
|
#### User Groups
|
|
1. Administrators
|
|
- Full system access
|
|
- Configuration management
|
|
- User management
|
|
|
|
2. Moderators
|
|
- Content moderation
|
|
- User management
|
|
- Report handling
|
|
|
|
3. Company Representatives
|
|
- Company profile management
|
|
- Official updates
|
|
- Response management
|
|
|
|
4. Regular Users
|
|
- Content creation
|
|
- Review submission
|
|
- Media uploads
|
|
|
|
#### Permission Matrix
|
|
```python
|
|
ROLE_PERMISSIONS = {
|
|
'administrator': [
|
|
'can_manage_users',
|
|
'can_configure_system',
|
|
'can_moderate_content',
|
|
],
|
|
'moderator': [
|
|
'can_moderate_content',
|
|
'can_manage_reports',
|
|
'can_verify_information',
|
|
],
|
|
'company_rep': [
|
|
'can_manage_company',
|
|
'can_post_updates',
|
|
'can_respond_reviews',
|
|
],
|
|
'user': [
|
|
'can_create_content',
|
|
'can_submit_reviews',
|
|
'can_upload_media',
|
|
],
|
|
}
|
|
```
|
|
|
|
## Security Controls
|
|
|
|
### Request Security
|
|
|
|
#### CSRF Protection
|
|
```python
|
|
MIDDLEWARE = [
|
|
'django.middleware.csrf.CsrfViewMiddleware',
|
|
]
|
|
|
|
# Template configuration
|
|
{% csrf_token %}
|
|
|
|
# AJAX request handling
|
|
headers: {
|
|
'X-CSRFToken': getCookie('csrftoken')
|
|
}
|
|
```
|
|
|
|
#### XSS Prevention
|
|
```python
|
|
# Template autoescape
|
|
{% autoescape on %}
|
|
{{ user_content }}
|
|
{% endautoescape %}
|
|
|
|
# Content Security Policy
|
|
CSP_DEFAULT_SRC = ("'self'",)
|
|
CSP_SCRIPT_SRC = ("'self'",)
|
|
CSP_STYLE_SRC = ("'self'", "'unsafe-inline'")
|
|
CSP_IMG_SRC = ("'self'", "data:", "https:")
|
|
```
|
|
|
|
### Data Protection
|
|
|
|
#### Password Security
|
|
```python
|
|
# Password validation
|
|
AUTH_PASSWORD_VALIDATORS = [
|
|
{
|
|
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
|
},
|
|
{
|
|
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
|
'OPTIONS': {
|
|
'min_length': 12,
|
|
}
|
|
},
|
|
{
|
|
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
|
},
|
|
{
|
|
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
|
},
|
|
]
|
|
```
|
|
|
|
#### Data Encryption
|
|
```python
|
|
# Database encryption
|
|
ENCRYPTED_FIELDS = {
|
|
'fields': {
|
|
'users.User.ssn': 'django_cryptography.fields.encrypt',
|
|
'payment.Card.number': 'django_cryptography.fields.encrypt',
|
|
},
|
|
}
|
|
|
|
# File encryption
|
|
ENCRYPTED_FILE_STORAGE = 'django_cryptography.storage.EncryptedFileSystemStorage'
|
|
```
|
|
|
|
### Session Security
|
|
|
|
#### Session Configuration
|
|
```python
|
|
# Session settings
|
|
SESSION_COOKIE_SECURE = True
|
|
SESSION_COOKIE_HTTPONLY = True
|
|
SESSION_COOKIE_SAMESITE = 'Lax'
|
|
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'
|
|
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
|
|
```
|
|
|
|
#### Session Management
|
|
```python
|
|
# Session cleanup
|
|
CELERYBEAT_SCHEDULE = {
|
|
'cleanup-expired-sessions': {
|
|
'task': 'core.tasks.cleanup_expired_sessions',
|
|
'schedule': crontab(hour=4, minute=0)
|
|
},
|
|
}
|
|
```
|
|
|
|
## API Security
|
|
|
|
### Authentication
|
|
```python
|
|
REST_FRAMEWORK = {
|
|
'DEFAULT_AUTHENTICATION_CLASSES': [
|
|
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
|
|
'rest_framework.authentication.SessionAuthentication',
|
|
],
|
|
'DEFAULT_PERMISSION_CLASSES': [
|
|
'rest_framework.permissions.IsAuthenticated',
|
|
],
|
|
}
|
|
```
|
|
|
|
### Rate Limiting
|
|
```python
|
|
# Rate limiting configuration
|
|
REST_FRAMEWORK = {
|
|
'DEFAULT_THROTTLE_CLASSES': [
|
|
'rest_framework.throttling.AnonRateThrottle',
|
|
'rest_framework.throttling.UserRateThrottle'
|
|
],
|
|
'DEFAULT_THROTTLE_RATES': {
|
|
'anon': '100/day',
|
|
'user': '1000/day'
|
|
}
|
|
}
|
|
```
|
|
|
|
## Security Headers
|
|
|
|
### HTTP Security Headers
|
|
```python
|
|
MIDDLEWARE = [
|
|
'django.middleware.security.SecurityMiddleware',
|
|
]
|
|
|
|
SECURE_HSTS_SECONDS = 31536000
|
|
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
|
|
SECURE_HSTS_PRELOAD = True
|
|
SECURE_SSL_REDIRECT = True
|
|
SECURE_REFERRER_POLICY = 'same-origin'
|
|
SECURE_BROWSER_XSS_FILTER = True
|
|
```
|
|
|
|
## File Upload Security
|
|
|
|
### Upload Configuration
|
|
```python
|
|
# File upload settings
|
|
FILE_UPLOAD_MAX_MEMORY_SIZE = 2621440 # 2.5 MB
|
|
FILE_UPLOAD_PERMISSIONS = 0o644
|
|
ALLOWED_EXTENSIONS = ['jpg', 'jpeg', 'png', 'gif']
|
|
|
|
def validate_file_extension(value):
|
|
ext = os.path.splitext(value.name)[1]
|
|
if not ext.lower() in ALLOWED_EXTENSIONS:
|
|
raise ValidationError('Unsupported file extension.')
|
|
```
|
|
|
|
### Media Security
|
|
```python
|
|
# Serve media files securely
|
|
@login_required
|
|
def serve_protected_file(request, path):
|
|
if not request.user.has_perm('can_access_file'):
|
|
raise PermissionDenied
|
|
response = serve(request, path, document_root=settings.MEDIA_ROOT)
|
|
response['Content-Disposition'] = 'attachment'
|
|
return response
|
|
```
|
|
|
|
## Security Monitoring
|
|
|
|
### Audit Logging
|
|
```python
|
|
# Audit log configuration
|
|
AUDIT_LOG_HANDLERS = {
|
|
'security': {
|
|
'level': 'INFO',
|
|
'class': 'logging.handlers.RotatingFileHandler',
|
|
'filename': 'logs/security.log',
|
|
'maxBytes': 1024*1024*5, # 5 MB
|
|
'backupCount': 5,
|
|
},
|
|
}
|
|
|
|
# Audit log usage
|
|
def log_security_event(event_type, user, details):
|
|
logger.info(f'Security event: {event_type}', extra={
|
|
'user_id': user.id,
|
|
'ip_address': get_client_ip(request),
|
|
'details': details
|
|
})
|
|
```
|
|
|
|
### Security Alerts
|
|
```python
|
|
# Alert configuration
|
|
SECURITY_ALERTS = {
|
|
'login_attempts': {
|
|
'threshold': 5,
|
|
'window': 300, # 5 minutes
|
|
'action': 'account_lock'
|
|
},
|
|
'api_errors': {
|
|
'threshold': 100,
|
|
'window': 3600, # 1 hour
|
|
'action': 'notify_admin'
|
|
}
|
|
}
|
|
```
|
|
|
|
## Incident Response
|
|
|
|
### Security Incident Workflow
|
|
1. Detection
|
|
2. Analysis
|
|
3. Containment
|
|
4. Eradication
|
|
5. Recovery
|
|
6. Lessons Learned
|
|
|
|
### Response Actions
|
|
```python
|
|
class SecurityIncident:
|
|
def contain_threat(self):
|
|
# Lock affected accounts
|
|
# Block suspicious IPs
|
|
# Disable compromised tokens
|
|
|
|
def investigate(self):
|
|
# Collect logs
|
|
# Analyze patterns
|
|
# Document findings
|
|
|
|
def recover(self):
|
|
# Restore systems
|
|
# Reset credentials
|
|
# Update security controls |