- 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
281 lines
5.4 KiB
Markdown
281 lines
5.4 KiB
Markdown
# 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.
|
|
|
|
```sql
|
|
-- 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**
|
|
|
|
```javascript
|
|
// 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.
|
|
|
|
```html
|
|
<!-- Gefährlich: Benutzereingabe direkt ausgeben -->
|
|
<div>{{ benutzereingabe }}</div>
|
|
<!-- Bei eingabe = <script>alert('XSS')</script> -->
|
|
```
|
|
|
|
**Schutz: Output Encoding**
|
|
|
|
```javascript
|
|
// HTML-Escaping
|
|
function escapeHtml(text) {
|
|
const map = {
|
|
'&': '&',
|
|
'<': '<',
|
|
'>': '>',
|
|
'"': '"',
|
|
"'": '''
|
|
};
|
|
return text.replace(/[&<>"']/g, m => map[m]);
|
|
}
|
|
|
|
// React macht das automatisch
|
|
<div>{benutzereingabe}</div>
|
|
```
|
|
|
|
### Content Security Policy (CSP)
|
|
|
|
```http
|
|
Content-Security-Policy: default-src 'self'; script-src 'self'
|
|
```
|
|
|
|
### Praktisches Beispiel: Express.js Sicherheits-Header
|
|
|
|
```javascript
|
|
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
|
|
|
|
```javascript
|
|
// 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
|
|
|
|
```javascript
|
|
// 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
|
|
|
|
```http
|
|
# 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
|
|
|
|
```javascript
|
|
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
|
|
|
|
```javascript
|
|
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
|
|
|
|
- [[LF6-03-Backend|Zurück: Backend-Entwicklung]]
|
|
- [[LF4-IT-Sicherheit|IT-Sicherheit allgemein]]
|
|
- [[LF3-05-Datenbankmanagement|Datenbank: SQL Injection]]
|
|
|
|
---
|
|
|
|
*Stand: 2024*
|