# 🔒 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.