469 lines
11 KiB
Markdown
469 lines
11 KiB
Markdown
# Security Best Practices Guide
|
|
|
|
This guide covers security configurations and best practices for deploying and operating Readur in production environments.
|
|
|
|
## Authentication and Authorization
|
|
|
|
### Authentication Setup
|
|
|
|
Readur supports multiple authentication methods to secure your document management system:
|
|
|
|
#### Local Authentication
|
|
|
|
```yaml
|
|
# Basic authentication configuration
|
|
AUTH_SECRET: "your-secure-random-secret-min-32-chars"
|
|
SESSION_SECRET: "your-session-secret-min-32-chars"
|
|
```
|
|
|
|
Generate secure secrets:
|
|
```bash
|
|
# Generate auth secret
|
|
openssl rand -hex 32
|
|
|
|
# Generate session secret
|
|
openssl rand -base64 32
|
|
```
|
|
|
|
#### OIDC/SSO Integration
|
|
|
|
Configure OpenID Connect for enterprise SSO:
|
|
|
|
```yaml
|
|
OIDC_ENABLED: "true"
|
|
OIDC_CLIENT_ID: "readur-client"
|
|
OIDC_CLIENT_SECRET: "your-client-secret"
|
|
OIDC_ISSUER_URL: "https://auth.example.com/realms/readur"
|
|
OIDC_REDIRECT_URI: "https://readur.example.com/api/auth/oidc/callback"
|
|
OIDC_SCOPES: "openid profile email"
|
|
```
|
|
|
|
### Role-Based Access Control
|
|
|
|
Readur implements three user roles with distinct permissions:
|
|
|
|
| Role | Permissions |
|
|
|------|------------|
|
|
| Admin | Full system access, user management, configuration changes |
|
|
| Editor | Document upload, edit, delete, OCR management |
|
|
| Viewer | Read-only access to documents and search |
|
|
|
|
Configure default role for new users:
|
|
```yaml
|
|
DEFAULT_USER_ROLE: "viewer"
|
|
AUTO_CREATE_USERS: "false"
|
|
```
|
|
|
|
### Session Management
|
|
|
|
Configure session security parameters:
|
|
|
|
```yaml
|
|
SESSION_TIMEOUT: 3600 # Seconds (1 hour)
|
|
SESSION_COOKIE_SECURE: "true" # HTTPS only
|
|
SESSION_COOKIE_HTTPONLY: "true" # Prevent XSS
|
|
SESSION_COOKIE_SAMESITE: "strict" # CSRF protection
|
|
```
|
|
|
|
## File Upload Security
|
|
|
|
### Size Limits
|
|
|
|
Prevent resource exhaustion attacks:
|
|
|
|
```yaml
|
|
MAX_FILE_SIZE_MB: 100 # Maximum file size
|
|
MAX_FILES_PER_UPLOAD: 10 # Batch upload limit
|
|
TOTAL_STORAGE_QUOTA_GB: 1000 # Per-user quota
|
|
```
|
|
|
|
### File Type Validation
|
|
|
|
Restrict allowed file types:
|
|
|
|
```yaml
|
|
ALLOWED_FILE_TYPES: "pdf,png,jpg,jpeg,txt,doc,docx"
|
|
BLOCK_EXECUTABLE_FILES: "true"
|
|
SCAN_FOR_MALWARE: "true" # Requires ClamAV integration
|
|
```
|
|
|
|
### Upload Validation
|
|
|
|
```rust
|
|
// Example validation implementation
|
|
fn validate_upload(file: &UploadedFile) -> Result<(), SecurityError> {
|
|
// Check file size
|
|
if file.size > MAX_FILE_SIZE {
|
|
return Err(SecurityError::FileTooLarge);
|
|
}
|
|
|
|
// Validate MIME type
|
|
let detected_mime = magic::from_buffer(&file.data)?;
|
|
if !ALLOWED_MIME_TYPES.contains(&detected_mime) {
|
|
return Err(SecurityError::InvalidFileType);
|
|
}
|
|
|
|
// Check for malicious content
|
|
if contains_suspicious_patterns(&file.data) {
|
|
return Err(SecurityError::MaliciousContent);
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
```
|
|
|
|
## Network Security
|
|
|
|
### TLS Configuration
|
|
|
|
Always use HTTPS in production:
|
|
|
|
```nginx
|
|
server {
|
|
listen 443 ssl http2;
|
|
ssl_certificate /etc/ssl/certs/readur.crt;
|
|
ssl_certificate_key /etc/ssl/private/readur.key;
|
|
|
|
# Modern TLS configuration
|
|
ssl_protocols TLSv1.2 TLSv1.3;
|
|
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
|
|
ssl_prefer_server_ciphers off;
|
|
|
|
# HSTS
|
|
add_header Strict-Transport-Security "max-age=63072000" always;
|
|
}
|
|
```
|
|
|
|
### CORS Configuration
|
|
|
|
Configure Cross-Origin Resource Sharing:
|
|
|
|
```yaml
|
|
CORS_ENABLED: "true"
|
|
CORS_ALLOWED_ORIGINS: "https://app.example.com,https://admin.example.com"
|
|
CORS_ALLOWED_METHODS: "GET,POST,PUT,DELETE,OPTIONS"
|
|
CORS_MAX_AGE: 3600
|
|
```
|
|
|
|
### Rate Limiting
|
|
|
|
Prevent abuse and DoS attacks:
|
|
|
|
```yaml
|
|
RATE_LIMIT_ENABLED: "true"
|
|
RATE_LIMIT_REQUESTS_PER_MINUTE: 100
|
|
RATE_LIMIT_BURST_SIZE: 20
|
|
RATE_LIMIT_EXCLUDE_PATHS: "/health,/metrics"
|
|
```
|
|
|
|
## Secrets Management
|
|
|
|
### Environment Variables
|
|
|
|
Never commit secrets to version control:
|
|
|
|
```bash
|
|
# .env.example (commit this)
|
|
DATABASE_URL=postgresql://user:password@localhost/readur
|
|
AUTH_SECRET=change-this-secret
|
|
S3_ACCESS_KEY=your-access-key
|
|
S3_SECRET_KEY=your-secret-key
|
|
|
|
# .env (don't commit - add to .gitignore)
|
|
DATABASE_URL=postgresql://readur:SecurePass123!@db.internal/readur_prod
|
|
AUTH_SECRET=a8f7d9s8f7sd9f87sd9f87sd9f8s7df98s7df98s7df9
|
|
S3_ACCESS_KEY=AKIAIOSFODNN7EXAMPLE
|
|
S3_SECRET_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
|
|
```
|
|
|
|
### Secret Rotation
|
|
|
|
Implement regular secret rotation:
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
# rotate-secrets.sh
|
|
|
|
# Generate new secrets
|
|
NEW_AUTH_SECRET=$(openssl rand -hex 32)
|
|
NEW_SESSION_SECRET=$(openssl rand -base64 32)
|
|
|
|
# Update application configuration
|
|
kubectl create secret generic readur-secrets \
|
|
--from-literal=auth-secret="$NEW_AUTH_SECRET" \
|
|
--from-literal=session-secret="$NEW_SESSION_SECRET" \
|
|
--dry-run=client -o yaml | kubectl apply -f -
|
|
|
|
# Restart application
|
|
kubectl rollout restart deployment/readur
|
|
```
|
|
|
|
### Vault Integration
|
|
|
|
For production, use HashiCorp Vault or similar:
|
|
|
|
```yaml
|
|
VAULT_ENABLED: "true"
|
|
VAULT_ADDR: "https://vault.internal:8200"
|
|
VAULT_TOKEN: "s.xxxxxxxxxxxxxxxx"
|
|
VAULT_PATH: "secret/data/readur"
|
|
```
|
|
|
|
## Data Encryption
|
|
|
|
### Encryption at Rest
|
|
|
|
Database encryption:
|
|
|
|
```sql
|
|
-- PostgreSQL transparent data encryption
|
|
ALTER SYSTEM SET ssl = on;
|
|
ALTER SYSTEM SET ssl_cert_file = '/etc/postgresql/server.crt';
|
|
ALTER SYSTEM SET ssl_key_file = '/etc/postgresql/server.key';
|
|
```
|
|
|
|
S3 storage encryption:
|
|
|
|
```yaml
|
|
S3_ENCRYPTION_ENABLED: "true"
|
|
S3_ENCRYPTION_TYPE: "AES256" # or "aws:kms"
|
|
S3_KMS_KEY_ID: "arn:aws:kms:region:account:key/xxxxx"
|
|
```
|
|
|
|
### Encryption in Transit
|
|
|
|
All data transmissions must be encrypted:
|
|
|
|
```yaml
|
|
# Database connections
|
|
DATABASE_SSL_MODE: "require"
|
|
DATABASE_SSL_CERT: "/etc/ssl/certs/db-cert.pem"
|
|
|
|
# S3 connections
|
|
S3_USE_SSL: "true"
|
|
S3_VERIFY_SSL: "true"
|
|
|
|
# Redis connections (if used)
|
|
REDIS_TLS_ENABLED: "true"
|
|
REDIS_TLS_CERT: "/etc/ssl/certs/redis-cert.pem"
|
|
```
|
|
|
|
## Audit Logging
|
|
|
|
### Comprehensive Audit Trail
|
|
|
|
Configure audit logging for security events:
|
|
|
|
```yaml
|
|
AUDIT_LOG_ENABLED: "true"
|
|
AUDIT_LOG_LEVEL: "info"
|
|
AUDIT_LOG_PATH: "/var/log/readur/audit.log"
|
|
AUDIT_LOG_FORMAT: "json"
|
|
```
|
|
|
|
Audit log entry structure:
|
|
```json
|
|
{
|
|
"timestamp": "2025-01-15T10:30:45Z",
|
|
"event_type": "document_access",
|
|
"user_id": "user123",
|
|
"user_email": "user@example.com",
|
|
"action": "download",
|
|
"resource": "document/abc123",
|
|
"ip_address": "192.168.1.100",
|
|
"user_agent": "Mozilla/5.0...",
|
|
"result": "success",
|
|
"metadata": {
|
|
"document_name": "financial_report.pdf",
|
|
"file_size": 1048576
|
|
}
|
|
}
|
|
```
|
|
|
|
### Events to Audit
|
|
|
|
Critical events that must be logged:
|
|
- User authentication (success/failure)
|
|
- User registration
|
|
- Password changes
|
|
- Document uploads/downloads
|
|
- Document deletions
|
|
- Permission changes
|
|
- Configuration changes
|
|
- Admin actions
|
|
- Failed authorization attempts
|
|
- Suspicious activities
|
|
|
|
## Common Vulnerabilities and Mitigations
|
|
|
|
### SQL Injection Prevention
|
|
|
|
Always use parameterized queries:
|
|
|
|
```rust
|
|
// Safe query using sqlx
|
|
let document = sqlx::query_as!(
|
|
Document,
|
|
"SELECT * FROM documents WHERE id = $1 AND user_id = $2",
|
|
document_id,
|
|
user_id
|
|
)
|
|
.fetch_one(&pool)
|
|
.await?;
|
|
|
|
// Never do this!
|
|
// let query = format!("SELECT * FROM documents WHERE id = {}", id);
|
|
```
|
|
|
|
### XSS Prevention
|
|
|
|
Sanitize all user input:
|
|
|
|
```rust
|
|
use ammonia::clean;
|
|
|
|
fn sanitize_input(input: &str) -> String {
|
|
// Remove potentially dangerous HTML
|
|
clean(input)
|
|
}
|
|
|
|
// Content Security Policy headers
|
|
app.use(
|
|
DefaultHeaders::new()
|
|
.header("Content-Security-Policy", "default-src 'self'")
|
|
.header("X-Content-Type-Options", "nosniff")
|
|
.header("X-Frame-Options", "DENY")
|
|
.header("X-XSS-Protection", "1; mode=block")
|
|
);
|
|
```
|
|
|
|
### CSRF Protection
|
|
|
|
Implement CSRF tokens:
|
|
|
|
```rust
|
|
// Generate CSRF token
|
|
let csrf_token = generate_csrf_token(&session);
|
|
|
|
// Validate on form submission
|
|
if !validate_csrf_token(&request.csrf_token, &session) {
|
|
return Err(SecurityError::InvalidCSRFToken);
|
|
}
|
|
```
|
|
|
|
### Directory Traversal Prevention
|
|
|
|
Validate file paths:
|
|
|
|
```rust
|
|
use std::path::{Path, Component};
|
|
|
|
fn safe_path(user_input: &str) -> Result<PathBuf, SecurityError> {
|
|
let path = Path::new(user_input);
|
|
|
|
// Check for directory traversal attempts
|
|
for component in path.components() {
|
|
match component {
|
|
Component::ParentDir => return Err(SecurityError::PathTraversal),
|
|
Component::RootDir => return Err(SecurityError::AbsolutePath),
|
|
_ => {}
|
|
}
|
|
}
|
|
|
|
Ok(path.to_path_buf())
|
|
}
|
|
```
|
|
|
|
## Security Headers
|
|
|
|
Configure security headers in your reverse proxy:
|
|
|
|
```nginx
|
|
# Security headers
|
|
add_header X-Content-Type-Options "nosniff" always;
|
|
add_header X-Frame-Options "SAMEORIGIN" always;
|
|
add_header X-XSS-Protection "1; mode=block" always;
|
|
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
|
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';" always;
|
|
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
|
|
```
|
|
|
|
## Security Checklist
|
|
|
|
### Pre-Deployment Checklist
|
|
|
|
- [ ] All secrets are properly managed (not in code)
|
|
- [ ] TLS/SSL certificates are valid and configured
|
|
- [ ] Authentication is properly configured
|
|
- [ ] File upload restrictions are in place
|
|
- [ ] Rate limiting is enabled
|
|
- [ ] CORS is properly configured
|
|
- [ ] Security headers are set
|
|
- [ ] Audit logging is enabled
|
|
- [ ] Database connections use SSL
|
|
- [ ] Default passwords are changed
|
|
- [ ] Unnecessary ports are closed
|
|
- [ ] Error messages don't leak sensitive information
|
|
|
|
### Regular Security Tasks
|
|
|
|
- [ ] Review audit logs weekly
|
|
- [ ] Update dependencies monthly
|
|
- [ ] Rotate secrets quarterly
|
|
- [ ] Conduct security assessments annually
|
|
- [ ] Test backup restoration procedures
|
|
- [ ] Review user permissions
|
|
- [ ] Monitor for suspicious activities
|
|
- [ ] Update TLS certificates before expiry
|
|
|
|
## Security Monitoring
|
|
|
|
### Key Metrics to Monitor
|
|
|
|
```yaml
|
|
# Prometheus alerts
|
|
groups:
|
|
- name: security
|
|
rules:
|
|
- alert: HighFailedLoginRate
|
|
expr: rate(auth_failures_total[5m]) > 10
|
|
annotations:
|
|
summary: "High rate of failed login attempts"
|
|
|
|
- alert: UnusualFileUploadVolume
|
|
expr: rate(file_uploads_total[1h]) > 100
|
|
annotations:
|
|
summary: "Unusual file upload activity detected"
|
|
|
|
- alert: SuspiciousAPIUsage
|
|
expr: rate(api_requests_total{status="403"}[5m]) > 20
|
|
annotations:
|
|
summary: "High rate of forbidden API requests"
|
|
```
|
|
|
|
## Incident Response
|
|
|
|
### Security Incident Procedure
|
|
|
|
1. **Detection**: Identify the security incident
|
|
2. **Containment**: Isolate affected systems
|
|
3. **Investigation**: Determine scope and impact
|
|
4. **Eradication**: Remove the threat
|
|
5. **Recovery**: Restore normal operations
|
|
6. **Lessons Learned**: Document and improve
|
|
|
|
### Emergency Contacts
|
|
|
|
Maintain an updated contact list:
|
|
- Security team lead
|
|
- System administrators
|
|
- Database administrators
|
|
- Cloud provider support
|
|
- Legal counsel (if needed)
|
|
|
|
## Additional Resources
|
|
|
|
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
|
|
- [CIS Security Benchmarks](https://www.cisecurity.org/cis-benchmarks/)
|
|
- [NIST Cybersecurity Framework](https://www.nist.gov/cyberframework)
|
|
- [PostgreSQL Security Documentation](https://www.postgresql.org/docs/current/security.html) |