Files
Ninjaserver/wiki/Sicherheit.md
2025-09-23 14:13:24 +02:00

622 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 🔒 Sicherheit
Sicherheitsrichtlinien und Best Practices für das Ninja Cross Parkour System.
## 📋 Inhaltsverzeichnis
- [🛡️ Sicherheitsübersicht](#-sicherheitsübersicht)
- [🔐 Authentifizierung](#-authentifizierung)
- [🔑 Autorisierung](#-autorisierung)
- [🛡️ Datenverschlüsselung](#-datenverschlüsselung)
- [🌐 Netzwerksicherheit](#-netzwerksicherheit)
- [🗄️ Datenbanksicherheit](#-datenbanksicherheit)
- [📱 API-Sicherheit](#-api-sicherheit)
- [🔍 Monitoring](#-monitoring)
- [🚨 Incident Response](#-incident-response)
## 🛡️ Sicherheitsübersicht
### Sicherheitsprinzipien
- **Defense in Depth** - Mehrschichtige Sicherheit
- **Least Privilege** - Minimale Berechtigungen
- **Zero Trust** - Kein Vertrauen ohne Verifikation
- **Security by Design** - Sicherheit von Anfang an
### Bedrohungsmodell
- **Externe Angriffe** - Unbefugter Zugriff von außen
- **Interne Bedrohungen** - Missbrauch durch autorisierte Benutzer
- **Datenlecks** - Unbefugte Offenlegung von Daten
- **Service-Ausfälle** - Verfügbarkeitsprobleme
## 🔐 Authentifizierung
### Passwort-Sicherheit
```javascript
// Passwort-Hashing mit bcrypt
const bcrypt = require('bcrypt');
// Passwort hashen
const saltRounds = 12;
const hashedPassword = await bcrypt.hash(password, saltRounds);
// Passwort verifizieren
const isValid = await bcrypt.compare(password, hashedPassword);
```
### Passwort-Richtlinien
- **Mindestlänge:** 12 Zeichen
- **Komplexität:** Groß-/Kleinbuchstaben, Zahlen, Sonderzeichen
- **Keine Wörterbuchwörter**
- **Regelmäßige Rotation** (alle 90 Tage)
### Multi-Faktor-Authentifizierung (MFA)
```javascript
// TOTP-Implementierung
const speakeasy = require('speakeasy');
// Secret generieren
const secret = speakeasy.generateSecret({
name: 'Ninja Parkour',
account: 'admin@example.com'
});
// Token verifizieren
const verified = speakeasy.totp.verify({
secret: secret.base32,
encoding: 'base32',
token: userToken,
window: 2
});
```
### Session-Management
```javascript
// Sichere Session-Konfiguration
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
secure: process.env.NODE_ENV === 'production',
httpOnly: true,
maxAge: 24 * 60 * 60 * 1000, // 24 Stunden
sameSite: 'strict'
}
}));
```
## 🔑 Autorisierung
### Rollenbasierte Zugriffskontrolle (RBAC)
```javascript
// Rollen definieren
const ROLES = {
ADMIN: 'admin',
MODERATOR: 'moderator',
USER: 'user',
GUEST: 'guest'
};
// Berechtigungen definieren
const PERMISSIONS = {
READ_PLAYERS: 'read:players',
WRITE_PLAYERS: 'write:players',
DELETE_PLAYERS: 'delete:players',
READ_TIMES: 'read:times',
WRITE_TIMES: 'write:times',
ADMIN_ACCESS: 'admin:access'
};
// Rollen-Berechtigungen
const rolePermissions = {
[ROLES.ADMIN]: Object.values(PERMISSIONS),
[ROLES.MODERATOR]: [
PERMISSIONS.READ_PLAYERS,
PERMISSIONS.WRITE_PLAYERS,
PERMISSIONS.READ_TIMES,
PERMISSIONS.WRITE_TIMES
],
[ROLES.USER]: [
PERMISSIONS.READ_PLAYERS,
PERMISSIONS.READ_TIMES
]
};
```
### API-Key-Management
```javascript
// API-Key generieren
const generateAPIKey = () => {
return crypto.randomBytes(32).toString('hex');
};
// API-Key validieren
const validateAPIKey = async (apiKey) => {
const token = await db.query(
'SELECT * FROM api_tokens WHERE token = $1 AND is_active = true',
[apiKey]
);
return token.rows.length > 0;
};
// Berechtigungen prüfen
const checkPermission = (userRole, requiredPermission) => {
const userPermissions = rolePermissions[userRole] || [];
return userPermissions.includes(requiredPermission);
};
```
### Middleware für Autorisierung
```javascript
// Authentifizierung prüfen
const requireAuth = (req, res, next) => {
if (!req.session || !req.session.userId) {
return res.status(401).json({ error: 'Nicht authentifiziert' });
}
next();
};
// Rolle prüfen
const requireRole = (role) => {
return (req, res, next) => {
if (req.session.role !== role) {
return res.status(403).json({ error: 'Keine Berechtigung' });
}
next();
};
};
// Berechtigung prüfen
const requirePermission = (permission) => {
return (req, res, next) => {
const userRole = req.session.role;
if (!checkPermission(userRole, permission)) {
return res.status(403).json({ error: 'Keine Berechtigung' });
}
next();
};
};
```
## 🛡️ Datenverschlüsselung
### Verschlüsselung im Ruhezustand
```javascript
// Datenbank-Verschlüsselung
const crypto = require('crypto');
// Verschlüsselung
const encrypt = (text, key) => {
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipher('aes-256-cbc', key);
let encrypted = cipher.update(text, 'utf8', 'hex');
encrypted += cipher.final('hex');
return iv.toString('hex') + ':' + encrypted;
};
// Entschlüsselung
const decrypt = (text, key) => {
const textParts = text.split(':');
const iv = Buffer.from(textParts.shift(), 'hex');
const encryptedText = textParts.join(':');
const decipher = crypto.createDecipher('aes-256-cbc', key);
let decrypted = decipher.update(encryptedText, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
};
```
### Verschlüsselung in Bewegung
```javascript
// HTTPS-Konfiguration
const https = require('https');
const fs = require('fs');
const options = {
key: fs.readFileSync('private-key.pem'),
cert: fs.readFileSync('certificate.pem'),
ciphers: [
'ECDHE-RSA-AES256-GCM-SHA384',
'ECDHE-RSA-AES128-GCM-SHA256',
'ECDHE-RSA-AES256-SHA384',
'ECDHE-RSA-AES128-SHA256'
].join(':'),
honorCipherOrder: true
};
https.createServer(options, app).listen(443);
```
### Passwort-Verschlüsselung
```javascript
// Starke Passwort-Generierung
const generatePassword = (length = 16) => {
const charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*';
let password = '';
for (let i = 0; i < length; i++) {
password += charset.charAt(Math.floor(Math.random() * charset.length));
}
return password;
};
// Passwort-Stärke prüfen
const validatePassword = (password) => {
const minLength = 12;
const hasUpperCase = /[A-Z]/.test(password);
const hasLowerCase = /[a-z]/.test(password);
const hasNumbers = /\d/.test(password);
const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(password);
return password.length >= minLength &&
hasUpperCase &&
hasLowerCase &&
hasNumbers &&
hasSpecialChar;
};
```
## 🌐 Netzwerksicherheit
### Firewall-Konfiguration
```bash
# UFW-Firewall (Ubuntu)
sudo ufw enable
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Erlaubte Ports
sudo ufw allow 22/tcp # SSH
sudo ufw allow 80/tcp # HTTP
sudo ufw allow 443/tcp # HTTPS
sudo ufw allow 3000/tcp # App (nur intern)
# Rate Limiting
sudo ufw limit ssh
```
### DDoS-Schutz
```javascript
// Rate Limiting
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 Minuten
max: 100, // Max 100 Requests pro IP
message: 'Zu viele Anfragen von dieser IP',
standardHeaders: true,
legacyHeaders: false
});
app.use('/api/', limiter);
// Strikte Rate Limits für sensible Endpoints
const strictLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 5,
message: 'Zu viele Login-Versuche'
});
app.use('/api/login', strictLimiter);
```
### CORS-Konfiguration
```javascript
// Sichere CORS-Einstellungen
const cors = require('cors');
const corsOptions = {
origin: (origin, callback) => {
const allowedOrigins = [
'https://ninja.reptilfpv.de',
'https://www.ninja.reptilfpv.de'
];
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error('Nicht erlaubt durch CORS'));
}
},
credentials: true,
optionsSuccessStatus: 200
};
app.use(cors(corsOptions));
```
### SSL/TLS-Konfiguration
```javascript
// SSL-Redirect
app.use((req, res, next) => {
if (req.header('x-forwarded-proto') !== 'https') {
res.redirect(`https://${req.header('host')}${req.url}`);
} else {
next();
}
});
// Security Headers
const helmet = require('helmet');
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
scriptSrc: ["'self'"],
imgSrc: ["'self'", "data:", "https:"],
connectSrc: ["'self'"],
fontSrc: ["'self'"],
objectSrc: ["'none'"],
mediaSrc: ["'self'"],
frameSrc: ["'none'"]
}
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
}
}));
```
## 🗄️ Datenbanksicherheit
### Verbindungssicherheit
```javascript
// Sichere Datenbankverbindung
const dbConfig = {
host: process.env.DB_HOST,
port: process.env.DB_PORT,
database: process.env.DB_NAME,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
ssl: {
rejectUnauthorized: true,
ca: fs.readFileSync('ca-certificate.pem')
},
connectionTimeoutMillis: 5000,
idleTimeoutMillis: 30000,
max: 20
};
```
### SQL-Injection-Schutz
```javascript
// Parametrisierte Queries
const getUser = async (userId) => {
const query = 'SELECT * FROM players WHERE id = $1';
const values = [userId];
const result = await db.query(query, values);
return result.rows[0];
};
// Input-Validierung
const validateInput = (input) => {
if (typeof input !== 'string') {
throw new Error('Invalid input type');
}
// SQL-Injection-Patterns erkennen
const sqlPatterns = [
/(\b(SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|EXEC|UNION|SCRIPT)\b)/gi,
/(\b(OR|AND)\s+\d+\s*=\s*\d+)/gi,
/(\b(OR|AND)\s+['"]\s*=\s*['"])/gi
];
for (const pattern of sqlPatterns) {
if (pattern.test(input)) {
throw new Error('Potential SQL injection detected');
}
}
return input;
};
```
### Datenbank-Berechtigungen
```sql
-- Benutzer mit minimalen Rechten erstellen
CREATE USER ninja_app WITH PASSWORD 'secure_password';
-- Nur notwendige Berechtigungen gewähren
GRANT SELECT, INSERT, UPDATE, DELETE ON players TO ninja_app;
GRANT SELECT, INSERT, UPDATE, DELETE ON times TO ninja_app;
GRANT SELECT, INSERT, UPDATE, DELETE ON locations TO ninja_app;
GRANT SELECT, INSERT, UPDATE, DELETE ON achievements TO ninja_app;
GRANT SELECT, INSERT, UPDATE, DELETE ON player_achievements TO ninja_app;
-- Keine Admin-Rechte
REVOKE ALL ON SCHEMA public FROM ninja_app;
```
## 📱 API-Sicherheit
### Input-Validierung
```javascript
// Joi-Schema für Validierung
const Joi = require('joi');
const playerSchema = Joi.object({
firstname: Joi.string().min(2).max(50).required(),
lastname: Joi.string().min(2).max(50).required(),
birthdate: Joi.date().max('now').required(),
rfiduid: Joi.string().pattern(/^[A-F0-9:]{11}$/).optional()
});
const validatePlayer = (req, res, next) => {
const { error } = playerSchema.validate(req.body);
if (error) {
return res.status(400).json({ error: error.details[0].message });
}
next();
};
```
### API-Versionierung
```javascript
// API-Versionierung
app.use('/api/v1', v1Routes);
app.use('/api/v2', v2Routes);
// Deprecation-Warnungen
app.use('/api/v1', (req, res, next) => {
res.set('X-API-Version', '1.0.0');
res.set('X-API-Deprecated', 'false');
next();
});
```
### Request-Logging
```javascript
// Sicherheitsrelevante Logs
const securityLogger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new winston.transports.File({ filename: 'logs/security.log' })
]
});
// Login-Versuche loggen
app.post('/api/login', (req, res) => {
const { username, ip } = req.body;
securityLogger.info('Login attempt', { username, ip, timestamp: new Date() });
// ... Login-Logik
});
```
## 🔍 Monitoring
### Sicherheits-Monitoring
```javascript
// Anomalie-Erkennung
const detectAnomalies = (req, res, next) => {
const ip = req.ip;
const userAgent = req.get('User-Agent');
// Verdächtige Patterns erkennen
const suspiciousPatterns = [
/sqlmap/i,
/nikto/i,
/nmap/i,
/masscan/i
];
for (const pattern of suspiciousPatterns) {
if (pattern.test(userAgent)) {
securityLogger.warn('Suspicious user agent detected', { ip, userAgent });
return res.status(403).json({ error: 'Request blocked' });
}
}
next();
};
```
### Log-Analyse
```bash
# Sicherheitsrelevante Logs analysieren
grep "ERROR\|WARN\|SECURITY" logs/server.log | tail -100
# Failed Login-Versuche
grep "Login attempt" logs/security.log | grep "failed"
# Verdächtige Aktivitäten
grep "suspicious\|anomaly\|attack" logs/security.log
```
### Alerting
```javascript
// E-Mail-Benachrichtigungen
const nodemailer = require('nodemailer');
const transporter = nodemailer.createTransporter({
host: 'smtp.gmail.com',
port: 587,
secure: false,
auth: {
user: process.env.EMAIL_USER,
pass: process.env.EMAIL_PASS
}
});
const sendSecurityAlert = async (message) => {
await transporter.sendMail({
from: process.env.EMAIL_USER,
to: process.env.ADMIN_EMAIL,
subject: 'Security Alert - Ninja Parkour',
text: message
});
};
```
## 🚨 Incident Response
### Incident-Response-Plan
1. **Erkennung** - Monitoring und Alerts
2. **Bewertung** - Schweregrad bestimmen
3. **Eindämmung** - Schaden begrenzen
4. **Eliminierung** - Bedrohung entfernen
5. **Wiederherstellung** - System reparieren
6. **Lektionen** - Aus Fehlern lernen
### Notfall-Kontakte
- **Systemadministrator:** +49 123 456 789
- **Sicherheitsbeauftragter:** security@ninjaparkour.de
- **Management:** management@ninjaparkour.de
### Backup-Strategie
```bash
# Tägliche Backups
pg_dump -h localhost -U username -d ninjaserver | gzip > backup_$(date +%Y%m%d).sql.gz
# Wöchentliche Vollständige Backups
tar -czf full_backup_$(date +%Y%m%d).tar.gz /var/lib/postgresql/data/
# Backup-Verifizierung
psql -d ninjaserver < backup_$(date +%Y%m%d).sql
```
### Recovery-Prozeduren
```bash
# System wiederherstellen
sudo systemctl stop ninjaserver
psql -d ninjaserver < latest_backup.sql
sudo systemctl start ninjaserver
# Datenbank reparieren
psql -d ninjaserver -c "VACUUM FULL;"
psql -d ninjaserver -c "REINDEX DATABASE ninjaserver;"
```
## 🔧 Sicherheits-Checkliste
### Regelmäßige Überprüfungen
- [ ] Passwörter geändert (alle 90 Tage)
- [ ] API-Keys rotiert (alle 180 Tage)
- [ ] SSL-Zertifikate gültig
- [ ] Sicherheits-Updates installiert
- [ ] Logs überprüft
- [ ] Backups getestet
- [ ] Penetrationstests durchgeführt
### Wöchentliche Aufgaben
- [ ] Sicherheits-Logs analysiert
- [ ] System-Updates geprüft
- [ ] Backup-Status überprüft
- [ ] Performance-Metriken analysiert
### Monatliche Aufgaben
- [ ] Sicherheits-Audit durchgeführt
- [ ] Berechtigungen überprüft
- [ ] Incident-Response-Plan getestet
- [ ] Sicherheitsschulungen durchgeführt
---
**Wichtig:** Diese Sicherheitsrichtlinien müssen regelmäßig überprüft und aktualisiert werden. Bei Sicherheitsvorfällen wenden Sie sich sofort an den Sicherheitsbeauftragten.