Files
ihk-ausbildung/1-Ausbildungsjahr/LF6-Webanwendungen/LF6-04-Sicherheit-Web.md
Jan-Marlon Leibl 7df533c7a2 Add practical examples to multiple files
- LF9-03 Virtualisierung: Docker Compose + Volume examples
- LF6-02 Frontend: To-Do list practical example
- LF8-04 ETL: Complete ETL pipeline example
- LF6-04 Sicherheit: Express.js security headers
- LF2-04 Nutzwertanalyse: Cloud provider selection example
- LF9-04 Monitoring: Prometheus alerts + Python logging
2026-03-13 12:01:15 +01:00

5.4 KiB

6.4 Web-Sicherheit

OWASP Top 10

Die wichtigsten Sicherheitsrisiken

OWASP Top 10 (2021)
├── A01: Broken Access Control
├── A02: Cryptographic Failures
├── A03: Injection
├── A04: Insecure Design
├── A05: Security Misconfiguration
├── A06: Vulnerable Components
├── A07: Authentification Failures
├── A08: Software and Data Integrity Failures
├── A09: Security Logging Failures
└── A10: Server-Side Request Forgery

Injection

SQL Injection

Problem: Benutzereingaben werden direkt in SQL-Abfragen eingebaut.

-- Gefährlich
SELECT * FROM benutzer WHERE name = '" + name + "'

-- Bei name = "' OR '1'='1"
SELECT * FROM benutzer WHERE name = '' OR '1'='1'
-- → Alle Benutzer werden zurückgegeben!

Schutz: Prepared Statements

// Gefährlich
db.query("SELECT * FROM users WHERE name = '" + name + "'");

// Sicher - Parameterized Query
db.query("SELECT * FROM users WHERE name = ?", [name]);

XSS (Cross-Site Scripting)

Problem: Schadcode wird in Webseiten eingeschleust.

<!-- Gefährlich: Benutzereingabe direkt ausgeben -->
<div>{{ benutzereingabe }}</div>
<!-- Bei eingabe = <script>alert('XSS')</script> -->

Schutz: Output Encoding

// HTML-Escaping
function escapeHtml(text) {
    const map = {
        '&': '&amp;',
        '<': '&lt;',
        '>': '&gt;',
        '"': '&quot;',
        "'": '&#039;'
    };
    return text.replace(/[&<>"']/g, m => map[m]);
}

// React macht das automatisch
<div>{benutzereingabe}</div>

Content Security Policy (CSP)

Content-Security-Policy: default-src 'self'; script-src 'self'

Praktisches Beispiel: Express.js Sicherheits-Header

const helmet = require('helmet');
const cors = require('cors');

app.use(helmet());

// CORS konfigurieren
app.use(cors({
    origin: 'https://meine-app.de',
    credentials: true
}));

// Rate Limiting
const rateLimit = require('express-rate-limit');
app.use('/api/', rateLimit({
    windowMs: 15 * 60 * 1000, // 15 Minuten
    max: 100, // Max 100 Anfragen
    message: 'Zu viele Anfragen, bitte später versuchen'
}));

CSRF (Cross-Site Request Forgery)

Das Problem

CSRF-Angriff
1. Opfer ist eingeloggt bei bank.com
2. Opfer besucht bösartige Seite
3. Bösartige Seite sendet Request an bank.com
4. Browser sendet automatisch Session-Cookie
5. Überweisung wird ausgeführt

Schutz: CSRF-Token

// Server: Token generieren
app.get('/form', (req, res) => {
    const csrfToken = crypto.randomBytes(32).toString('hex');
    req.session.csrfToken = csrfToken;
    res.render('form', { csrfToken });
});

// Server: Token prüfen
app.post('/transfer', (req, res) => {
    if (req.body.csrfToken !== req.session.csrfToken) {
        return res.status(403).send('CSRF-Angriff erkannt');
    }
    // Weiter mit Überweisung...
});

Authentifizierung

Unsichere Praktiken

Vermeiden
├── Passwörter im Klartext speichern
├── Schwache Passwörter erlauben
├── Keine Zwei-Faktor-Authentifizierung
├── Session-IDs in URL
└── Unbegrenzte Login-Versuche

Sichere Authentifizierung

// 1. Passwörter hashen
const hash = await bcrypt.hash(passwort, 12);

// 2. Rate Limiting
const rateLimit = require('express-rate-limit');
app.use('/login', rateLimit({
    windowMs: 15 * 60 * 1000,
    max: 5 // 5 Versuche
}));

// 3. Sichere Session
app.use(session({
    secret: 'geheimer-schluessel',
    httpOnly: true,
    secure: true, // HTTPS
    sameSite: 'strict'
}));

Sicherheits-Header

Wichtige Header

# HSTS - HTTPS erzwingen
Strict-Transport-Security: max-age=31536000; includeSubDomains

# X-Content-Type-Options
X-Content-Type-Options: nosniff

# X-Frame-Options - Clickjacking
X-Frame-Options: DENY

# Content Security Policy
Content-Security-Policy: default-src 'self'

# Referrer Policy
Referrer-Policy: strict-origin-when-cross-origin

Implementierung in Express

const helmet = require('helmet');
app.use(helmet());

Eingabevalidierung

Grundprinzip

Validierung - Regeln
├── Nie Benutzereingaben vertrauen
├── Client-seitige Validierung reicht nicht
├── Whitelist statt Blacklist
├── Länge und Format prüfen
└── Alle Eingaben validieren

Validierungsbeispiel

const Joi = require('joi');

const benutzerSchema = Joi.object({
    name: Joi.string()
        .alphanum()
        .min(3)
        .max(30)
        .required(),

    email: Joi.string()
        .email()
        .required(),

    alter: Joi.number()
        .integer()
        .min(18)
        .max(150)
});

// Validierung
const { error, value } = benutzerSchema.validate(req.body);
if (error) {
    return res.status(400).json({ error: error.details });
}

Checkliste Web-Sicherheit

Sicherheits-Checkliste
□ HTTPS erzwingen
□ Sicherheits-Header setzen
□ SQL Injection verhindern (Prepared Statements)
□ XSS verhindern (Escaping)
□ CSRF-Token verwenden
□ Passwörter hashen (bcrypt)
□ Rate Limiting
□ Eingaben validieren
□ Fehlermeldungen nicht zu detailliert
□ Regelmäßige Updates
□ Sicherheitstests durchführen

Querverweise


Stand: 2024