Zum Hauptinhalt springen

Sicherheits-Protokollierung und Überwachung

Protokolle sind der Black Box Ihrer Infrastruktur. Wenn etwas schiefläuft — eine Datenpanne, ein Ausfall, unerklärliches Verhalten — sind Protokolle der Weg zu verstehen, was passiert ist. Ohne ordentliche Protokollierung untersuchen Sie Vorfälle im Dunkeln.

Sicherheitsüberwachung geht über Protokollierung hinaus: Statt darauf zu warten, dass jemand ein Problem bemerkt und Protokolle prüft, beobachten Sie aktiv verdächtige Muster und warnen in Echtzeit. Ein Brute-Force-Angriff, der Tausende fehlgeschlagener Logins erzeugt. Ein Admin-Konto, das plötzlich auf Daten zugreift, die es zuvor nie berührt hat. Ein Server, der Verbindungen zu bekannten bösartigen IPs herstellt.

Dieses Kapitel erklärt, wie Sie eine Protokollierungs- und Überwachungsinfrastruktur aufbauen, die Sicherheitsvorfälle erkennt, während sie geschehen, und nicht erst Wochen später, wenn der Schaden angerichtet ist.

Warum das für kleine Unternehmen wichtig ist

Kleine Unternehmen überspringen oft eine ordentliche Protokollierung. „Wir prüfen die Protokolle, wenn etwas kaputtgeht." Dieser Ansatz versagt für die Sicherheit:

Sie können nicht untersuchen, was Sie nicht protokolliert haben. Wenn eine Datenpanne entdeckt wird, ist die erste Frage: „Was ist passiert?" Ohne Protokolle können Sie das nicht beantworten. Sie wissen nicht, auf welche Daten zugegriffen wurde, wie Angreifer hereinkamen oder ob sie noch da sind.

Angreifer löschen ihre Spuren. Wenn Protokolle nur auf dem kompromittierten Server existieren, löschen Angreifer sie. Zentralisierte Protokollierung auf einem separaten System bewahrt Beweise, auch wenn Server kompromittiert werden.

Erkennung erfordert Sichtbarkeit. Die meisten Datenpannen bleiben monatelang unentdeckt. IBMs Bericht zu Kosten von Datenpannen 2024 stellte fest, dass die durchschnittliche Zeit zur Identifizierung einer Datenpanne 194 Tage beträgt. Unternehmen mit Sicherheitsüberwachung erkennen Datenpannen schneller und verlieren weniger Geld.

Compliance erfordert es oft. SOC 2, ISO 27001, HIPAA, PCI-DSS — alle erfordern Sicherheits-Protokollierung und Überwachung. Auch wenn Sie heute keine Compliance benötigen, könnte das später anders sein.

Kostenlose Tools sind ausgereift. ELK Stack, Grafana Loki, Graylog — das sind keine Spielzeuge. Sie verarbeiten Protokollierung im Enterprise-Maßstab. Sie brauchen kein 100.000-Dollar-SIEM für ordentliche Protokollierung.

Was protokolliert werden sollte

Nicht alle Protokolle sind für die Sicherheit gleich wichtig. Hier ist, was zählt:

Authentifizierung und Zugriff

| Ereignis | Warum es wichtig ist | Priorität | ||-------|---------------|----------| | Login-Erfolg/-Fehlschlag | Brute-Force-Erkennung, unbefugter Zugriff | Kritisch | | Passwortänderungen | Indikator für Kontoübernahme | Kritisch | | MFA-Ereignisse | Umgehungsversuche, Registrierungsänderungen | Kritisch | | Sitzungserstellung/-zerstörung | Sitzungs-Hijacking, anomale Zugriffsmuster | Hoch | | Berechtigungsänderungen | Privilege-Escalation, Insider-Bedrohungen | Kritisch | | API-Schlüsselnutzung | Kompromittierte Zugangsdaten | Hoch | | SSH/RDP-Verbindungen | Laterale Bewegung, erster Zugriff | Kritisch |

Anwendungssicherheit

| Ereignis | Warum es wichtig ist | Priorität | ||-------|---------------|----------| | Eingabevalidierungs-Fehlschläge | Angriffsversuche (SQLi, XSS) | Hoch | | Autorisierungs-Verweigerungen | Versuche, Zugriffskontrollen zu umgehen | Hoch | | Dateioperationen | Datenexfiltration, Ransomware | Mittel | | Zahlungs-/Transaktionsereignisse | Betrugserkennung | Kritisch | | Fehlerraten | Können auf Angriffe hinweisen | Mittel | | API-Rate-Limit-Treffer | Missbrauch, Scraping, DDoS | Mittel |

Infrastruktur

| Ereignis | Warum es wichtig ist | Priorität | ||-------|---------------|----------| | Firewall erlauben/ablehnen | Netzwerk-Reconnaissance, Angriffe | Hoch | | DNS-Anfragen | C2-Kommunikation, Datenexfiltration | Mittel | | Prozessausführung | Malware, Kryptomining | Hoch | | Dienst starten/stoppen | Manipulation, Persistenz | Mittel | | Dateiintegritäts-Änderungen | Rootkits, Backdoors | Hoch | | Cloud-API-Aufrufe | Ressourcenmissbrauch, Fehlkonfiguration | Hoch |

Was NICHT protokolliert werden sollte

Einige Daten sollten nie in Protokollen erscheinen:

  • Passwörter (auch fehlgeschlagene — protokollieren Sie „Authentifizierung fehlgeschlagen", nicht „Passwort 'abc123' war falsch")
  • Vollständige Kreditkartennummern (nur letzte 4 Ziffern protokollieren)
  • Sozialversicherungsnummern, Ausweisdokumente
  • Gesundheitsinformationen (PHI)
  • Sitzungs-Token, API-Schlüssel (protokollieren Sie, dass sie verwendet wurden, nicht ihre Werte)
  • Persönliche Daten über das Notwendige hinaus

Das Protokollieren sensibler Daten schafft ein neues Sicherheitsrisiko: Ihr Protokollspeicher wird zu einem wertvollen Angriffsziel.

Protokollformate und Standards

Konsistente Protokollformate erleichtern das Parsen und Alarmieren.

Strukturierte Protokollierung

Strukturierte Formate (JSON) statt reinem Text verwenden:

# BAD: Unstructured log
logger.info(f"User {user_id} logged in from {ip_address}")

# Output: 2024-01-15 10:23:45 INFO User 12345 logged in from 192.168.1.1
# Hard to parse, inconsistent format
# GOOD: Structured log
import structlog

logger = structlog.get_logger()
logger.info(
"user_login",
user_id=user_id,
ip_address=ip_address,
user_agent=request.headers.get("User-Agent"),
success=True
)

# Output (JSON):
# {"event": "user_login", "user_id": 12345, "ip_address": "192.168.1.1",
# "user_agent": "Mozilla/5.0...", "success": true, "timestamp": "2024-01-15T10:23:45Z"}

Strukturierte Protokolle ermöglichen:

  • Konsistentes Parsen über alle Anwendungen hinweg
  • Einfaches Filtern (z. B. „alle fehlgeschlagenen Logins von dieser IP anzeigen")
  • Automatische Feldextraktion in SIEM-Tools
  • Bessere Komprimierung und Speichereffizienz

Gemeinsame Protokollfelder

Jeder Protokolleintrag sollte enthalten:

{
"timestamp": "2024-01-15T10:23:45.123Z",
"level": "info",
"event": "user_login",
"service": "auth-api",
"environment": "production",
"host": "auth-api-1.internal",
"trace_id": "abc123def456",
"user_id": "12345",
"ip_address": "192.168.1.1",
"user_agent": "Mozilla/5.0...",
"success": true,
"duration_ms": 45
}

| Feld | Zweck | ||-------|---------| | timestamp | Wann es passiert ist (ISO 8601, UTC) | | level | Schweregrad (debug, info, warn, error, critical) | | event | Was passiert ist (konsistente Ereignisnamen verwenden) | | service | Welche Anwendung/welcher Dienst | | environment | prod, staging, dev | | host | Welcher Server/Container | | trace_id | Verwandte Ereignisse korrelieren | | user_id | Wer das Ereignis ausgelöst hat | | ip_address | Woher die Anfrage kam |

Protokoll-Ebenen

Protokoll-Ebenen konsistent verwenden:

| Ebene | Wann zu verwenden | Beispiel | ||-------|-------------|---------| | DEBUG | Detaillierte Diagnoseinformationen, nur in Dev | Variablenwerte, Funktionsaufrufe | | INFO | Normaler Betrieb | Benutzer angemeldet, Anfrage abgeschlossen | | WARN | Etwas Unerwartetes, aber behandelt | Rate-Limit-Annäherung, Wiederholung erfolgreich | | ERROR | Etwas ist fehlgeschlagen | Datenbankverbindung fehlgeschlagen, API-Fehler | | CRITICAL | Systemweiter Ausfall | Dienst ausgefallen, Datenverfälschung |

Sicherheitsereignisse sollten typischerweise INFO (normale Sicherheitsereignisse) oder WARN/ERROR (verdächtige/fehlgeschlagene Versuche) sein.

Zentralisierte Protokollierungs-Architektur

Protokolle, die über Dutzende von Servern verstreut sind, sind bei einem Vorfall nutzlos. Sie brauchen zentralisierte Sammlung.

Grundlegende Architektur

┌─────────────────────────────────────────────────────────────────────┐
│ Log Sources │
├─────────────────────────────────────────────────────────────────────┤
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Web App │ │ API │ │ Database│ │ Firewall│ │ Cloud │ │
│ │ Logs │ │ Logs │ │ Logs │ │ Logs │ │ Logs │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │
└───────┼────────────┼────────────┼────────────┼────────────┼─────────┘
│ │ │ │ │
└────────────┴────────────┴─────┬──────┴────────────┘


┌─────────────────────────┐
│ Log Collector │
│ (Fluentd, Filebeat, │
│ Vector, Fluent Bit) │
└───────────┬─────────────┘


┌─────────────────────────┐
│ Log Aggregator │
│ (Elasticsearch, Loki, │
│ CloudWatch, Graylog) │
└───────────┬─────────────┘

┌───────────┴───────────┐
│ │
▼ ▼
┌───────────────────┐ ┌───────────────────┐
│ Visualization │ │ Alerting │
│ (Kibana, Grafana)│ │ (AlertManager, │
│ │ │ PagerDuty) │
└───────────────────┘ └───────────────────┘

Komponenten erklärt

Protokollquellen: Alles, was Protokolle generiert — Anwendungen, Server, Netzwerkgeräte, Cloud-Dienste.

Protokoll-Sammler: Agenten, die auf jedem Server laufen, Protokolle sammeln und weiterleiten. Sie verarbeiten:

  • Protokolldatei-Tailing
  • Parsen und Anreicherung
  • Pufferung (wenn das Netzwerk ausfällt)
  • Komprimierung

Protokoll-Aggregator: Zentraler Speicher, der Protokolle empfängt, indiziert und speichert. Bietet:

  • Such-Fähigkeiten
  • Langfristige Aufbewahrung
  • Aggregation und Analyse

Visualisierung: Dashboards zum Erkunden von Protokollen, Erstellen von Abfragen, Untersuchen von Vorfällen.

Alarmierung: Regeln, die Benachrichtigungen auslösen, wenn verdächtige Muster erscheinen.

Kostenlose Protokollierungs-Stacks

Option 1: ELK Stack (Elasticsearch + Logstash + Kibana)

Der klassische Open-Source-Protokollierungs-Stack. Die Daten fließen in eine Richtung:

Server (emittieren Protokolle) → Filebeat (sammeln & versenden) → Logstash (parsen & verarbeiten) → Elasticsearch (speichern & indizieren) → Kibana (visualisieren & suchen)

Docker-Compose-Setup:

version: '3.8'
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.12.0
environment:
- discovery.type=single-node
- xpack.security.enabled=true
- ELASTIC_PASSWORD=changeme
- "ES_JAVA_OPTS=-Xms2g -Xmx2g"
volumes:
- elasticsearch-data:/usr/share/elasticsearch/data
ports:
- "9200:9200"
healthcheck:
test: curl -s http://localhost:9200 >/dev/null || exit 1
interval: 30s
timeout: 10s
retries: 5

kibana:
image: docker.elastic.co/kibana/kibana:8.12.0
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
- ELASTICSEARCH_USERNAME=kibana_system
- ELASTICSEARCH_PASSWORD=changeme
ports:
- "5601:5601"
depends_on:
elasticsearch:
condition: service_healthy

logstash:
image: docker.elastic.co/logstash/logstash:8.12.0
volumes:
- ./logstash/pipeline:/usr/share/logstash/pipeline
ports:
- "5044:5044" # Beats input
- "5000:5000" # TCP input
depends_on:
elasticsearch:
condition: service_healthy

volumes:
elasticsearch-data:

Logstash-Pipeline-Konfiguration:

# logstash/pipeline/main.conf
input {
beats {
port => 5044
}
tcp {
port => 5000
codec => json_lines
}
}

filter {
# Parse JSON logs
if [message] =~ /^\{/ {
json {
source => "message"
}
}

# Parse common log formats
if [type] == "nginx" {
grok {
match => { "message" => '%{COMBINEDAPACHELOG}' }
}
}

# GeoIP enrichment for IP addresses
if [ip_address] {
geoip {
source => "ip_address"
target => "geoip"
}
}

# Add security-relevant tags
if [event] == "login_failed" {
mutate {
add_tag => ["security", "authentication"]
}
}
}

output {
elasticsearch {
hosts => ["elasticsearch:9200"]
user => "elastic"
password => "changeme"
index => "logs-%{+YYYY.MM.dd}"
}
}

Filebeat-Konfiguration (auf jedem Server):

# /etc/filebeat/filebeat.yml
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/nginx/access.log
- /var/log/nginx/error.log
fields:
type: nginx

- type: log
enabled: true
paths:
- /var/log/auth.log
fields:
type: auth

- type: log
enabled: true
paths:
- /app/logs/*.json
json.keys_under_root: true
json.add_error_key: true
fields:
type: application

output.logstash:
hosts: ["logstash.internal:5044"]

# Or direct to Elasticsearch
# output.elasticsearch:
# hosts: ["elasticsearch.internal:9200"]
# username: "elastic"
# password: "changeme"

Vorteile:

  • Extrem leistungsstarke Suche und Analyse
  • Riesiges Ökosystem und Community
  • Skaliert auf Petabytes
  • Kostenlos und Open Source (Basislizenz)

Nachteile:

  • Ressourcenintensiv (braucht erheblich RAM für Elasticsearch)
  • Komplex zu betreiben im großen Maßstab
  • Einige Features erfordern kostenpflichtige Lizenz

Option 2: Grafana Loki + Promtail

Eine neuere, leichtgewichtigere Alternative. Gleicher linearer Fluss, weniger bewegliche Teile:

Server (emittieren Protokolle) → Promtail (sammeln & versenden) → Loki (speichern) → Grafana (visualisieren)

Docker-Compose-Setup:

version: '3.8'
services:
loki:
image: grafana/loki:2.9.3
ports:
- "3100:3100"
volumes:
- ./loki-config.yaml:/etc/loki/local-config.yaml
- loki-data:/loki
command: -config.file=/etc/loki/local-config.yaml

grafana:
image: grafana/grafana:10.3.1
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=changeme
volumes:
- grafana-data:/var/lib/grafana
depends_on:
- loki

promtail:
image: grafana/promtail:2.9.3
volumes:
- ./promtail-config.yaml:/etc/promtail/config.yml
- /var/log:/var/log:ro
command: -config.file=/etc/promtail/config.yml

volumes:
loki-data:
grafana-data:

Loki-Konfiguration:

# loki-config.yaml
auth_enabled: false

server:
http_listen_port: 3100

common:
path_prefix: /loki
storage:
filesystem:
chunks_directory: /loki/chunks
rules_directory: /loki/rules
replication_factor: 1
ring:
kvstore:
store: inmemory

schema_config:
configs:
- from: 2020-10-24
store: boltdb-shipper
object_store: filesystem
schema: v11
index:
prefix: index_
period: 24h

ruler:
alertmanager_url: http://alertmanager:9093

Promtail-Konfiguration:

# promtail-config.yaml
server:
http_listen_port: 9080
grpc_listen_port: 0

positions:
filename: /tmp/positions.yaml

clients:
- url: http://loki:3100/loki/api/v1/push

scrape_configs:
- job_name: system
static_configs:
- targets:
- localhost
labels:
job: varlogs
__path__: /var/log/*log

- job_name: nginx
static_configs:
- targets:
- localhost
labels:
job: nginx
__path__: /var/log/nginx/*.log
pipeline_stages:
- regex:
expression: '^(?P<remote_addr>[\d\.]+) - (?P<remote_user>\S+) \[(?P<time_local>.+)\] "(?P<method>\S+) (?P<request>\S+) (?P<protocol>\S+)" (?P<status>\d+)'
- labels:
method:
status:

- job_name: application
static_configs:
- targets:
- localhost
labels:
job: app
__path__: /app/logs/*.json
pipeline_stages:
- json:
expressions:
level: level
event: event
user_id: user_id
- labels:
level:
event:

Vorteile:

  • Viel ressourcenschonender als Elasticsearch
  • Native Grafana-Integration
  • Label-basierte Indizierung ist sehr effizient
  • Einfach einzurichten und zu betreiben

Nachteile:

  • Weniger leistungsstarke Volltextsuche als Elasticsearch
  • Kleineres Ökosystem
  • Neuer, weniger kampferprobt

Option 3: Graylog

Eine vollständige Protokollverwaltungslösung mit integrierten SIEM-ähnlichen Features:

version: '3.8'
services:
mongodb:
image: mongo:6
volumes:
- mongo-data:/data/db

opensearch:
image: opensearchproject/opensearch:2.11.0
environment:
- discovery.type=single-node
- plugins.security.disabled=true
- "OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g"
volumes:
- opensearch-data:/usr/share/opensearch/data

graylog:
image: graylog/graylog:5.2
environment:
- GRAYLOG_PASSWORD_SECRET=somesecretpasswordpepper
- GRAYLOG_ROOT_PASSWORD_SHA2=8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918
- GRAYLOG_HTTP_EXTERNAL_URI=http://localhost:9000/
- GRAYLOG_MONGODB_URI=mongodb://mongodb:27017/graylog
- GRAYLOG_ELASTICSEARCH_HOSTS=http://opensearch:9200
ports:
- "9000:9000" # Web interface
- "1514:1514" # Syslog TCP
- "1514:1514/udp" # Syslog UDP
- "12201:12201" # GELF TCP
- "12201:12201/udp" # GELF UDP
depends_on:
- mongodb
- opensearch

volumes:
mongo-data:
opensearch-data:

Vorteile:

  • Integrierte Alarmierung und SIEM-ähnliche Features
  • Benutzerfreundliche Oberfläche
  • Gut für Sicherheitsanwendungsfälle out-of-the-box
  • Unterstützt GELF (strukturiertes Protokollformat)

Nachteile:

  • Komplexere Architektur (erfordert MongoDB + OpenSearch)
  • Weniger flexibel als Raw-ELK
  • Einige erweiterte Features erfordern Enterprise-Lizenz

Cloud-native Optionen

Wenn Sie in der Cloud laufen, sind native Protokollierungsdienste oft die einfachste Wahl:

AWS CloudWatch Logs:

# Install CloudWatch agent
sudo yum install amazon-cloudwatch-agent

# Configure (wizard available)
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-config-wizard

Konfigurationsdatei:

{
"logs": {
"logs_collected": {
"files": {
"collect_list": [
{
"file_path": "/var/log/nginx/access.log",
"log_group_name": "nginx-access",
"log_stream_name": "{instance_id}"
},
{
"file_path": "/app/logs/*.json",
"log_group_name": "application",
"log_stream_name": "{instance_id}",
"timestamp_format": "%Y-%m-%dT%H:%M:%S"
}
]
}
}
}
}

GCP Cloud Logging:

Automatisch für GCE-Instanzen. Für Anwendungen die Bibliothek verwenden:

from google.cloud import logging

client = logging.Client()
logger = client.logger("my-application")

logger.log_struct({
"event": "user_login",
"user_id": "12345",
"success": True
}, severity="INFO")

Azure Monitor Logs:

Log Analytics-Arbeitsbereich und Azure Monitor-Agent verwenden.

Vergleichstabelle

| Feature | ELK Stack | Grafana Loki | Graylog | CloudWatch | GCP Logging | ||---------|-----------|--------------|---------|------------|-------------| | Kosten | Kostenlos (OSS) | Kostenlos (OSS) | Kostenlos (OSS) | Pro GB | Pro GB | | Einrichtungskomplexität | Hoch | Mittel | Mittel | Niedrig | Niedrig | | Ressourcenverbrauch | Hoch | Niedrig | Mittel | N/A | N/A | | Volltextsuche | Ausgezeichnet | Gut | Ausgezeichnet | Gut | Gut | | Alarmierung | Einrichtung erforderlich | Eingebaut | Eingebaut | Eingebaut | Eingebaut | | Aufbewahrung | Unbegrenzt | Unbegrenzt | Unbegrenzt | Konfigurierbar | Konfigurierbar | | Skalierbarkeit | Ausgezeichnet | Ausgezeichnet | Gut | Ausgezeichnet | Ausgezeichnet | | Am besten für | Große Maßstäbe, komplexe Abfragen | Kubernetes, Grafana-Benutzer | Sicherheitsfokus | AWS-Umgebungen | GCP-Umgebungen |

Warnungen einrichten

Protokolle sind nur nützlich, wenn Sie sie beobachten. Alarmierung verwandelt passive Protokolle in aktive Überwachung.

Warn-Kategorien

Kritisch — sofortige Reaktion erforderlich:

  • Mehrere fehlgeschlagene Logins gefolgt von Erfolg (Credential-Stuffing erfolgreich)
  • Admin-Benutzer von Nicht-Admin erstellt
  • Firewall deaktiviert
  • Verdächtige Prozessausführung (Kryptominer-Signaturen)
  • Verbindung zu bekannter bösartiger IP
  • Produktionsdatenbank von unbekannter IP zugegriffen

Hoch — innerhalb von Stunden untersuchen:

  • Laufende Brute-Force-Angriffe
  • Ungewöhnliche API-Nutzungsmuster
  • Admin-Zugriff außerhalb der Geschäftszeiten
  • Große Datenexporte
  • Privilege-Escalation-Ereignisse

Mittel — täglich überprüfen:

  • Überschrittener Schwellenwert für fehlgeschlagene Logins
  • Fehlerrate-Spitzen
  • Ungewöhnlicher geografischer Zugriff
  • Zertifikat-Ablaufwarnungen

Niedrig — wöchentliche Überprüfung:

  • Zugriff von neuen Geräten
  • Richtlinien-Verletzungsversuche
  • Geringfügige Konfigurationsänderungen

Beispiele für Warnregeln

ELK/Kibana-Alarmierung:

{
"trigger": {
"schedule": {
"interval": "1m"
}
},
"input": {
"search": {
"request": {
"indices": ["logs-*"],
"body": {
"query": {
"bool": {
"must": [
{ "match": { "event": "login_failed" } },
{ "range": { "@timestamp": { "gte": "now-5m" } } }
]
}
},
"aggs": {
"by_ip": {
"terms": { "field": "ip_address", "size": 10 }
}
}
}
}
}
},
"condition": {
"script": {
"source": "return ctx.payload.aggregations.by_ip.buckets.stream().anyMatch(b -> b.doc_count > 10)"
}
},
"actions": {
"notify_slack": {
"slack": {
"message": {
"to": ["#security-alerts"],
"text": "Brute force attack detected: {{ctx.payload.aggregations.by_ip.buckets}}"
}
}
}
}
}

Grafana Loki-Alarmierung (via Grafana):

# grafana/provisioning/alerting/rules.yaml
apiVersion: 1
groups:
- orgId: 1
name: security-alerts
folder: Security
interval: 1m
rules:
- uid: brute-force-detection
title: Brute Force Attack Detected
condition: C
data:
- refId: A
datasourceUid: loki
model:
expr: 'sum(rate({job="app"} |= "login_failed" [5m])) by (ip_address)'
- refId: B
datasourceUid: __expr__
model:
expression: A
type: reduce
reducer: last
- refId: C
datasourceUid: __expr__
model:
expression: B > 10
type: threshold
for: 5m
annotations:
summary: "Brute force attack from {{ $labels.ip_address }}"
labels:
severity: critical

AWS CloudWatch-Alarme:

# Create metric filter for failed logins
aws logs put-metric-filter \
--log-group-name application \
--filter-name failed-logins \
--filter-pattern '{ $.event = "login_failed" }' \
--metric-transformations \
metricName=FailedLogins,metricNamespace=Security,metricValue=1

# Create alarm
aws cloudwatch put-metric-alarm \
--alarm-name BruteForceDetection \
--metric-name FailedLogins \
--namespace Security \
--statistic Sum \
--period 300 \
--threshold 50 \
--comparison-operator GreaterThanThreshold \
--evaluation-periods 1 \
--alarm-actions arn:aws:sns:us-east-1:123456789:security-alerts

Erkennungsregeln für Sicherheit

Häufige Muster, auf die gewarnt werden sollte:

Authentifizierungsangriffe

# Failed login spike (brute force)
- name: brute_force_attack
query: |
event:login_failed | stats count() by ip_address | where count > 20
window: 5m
severity: high

# Successful login after many failures (compromise)
- name: credential_stuffing_success
query: |
(event:login_failed | stats count() as failures by user_id, ip_address)
| join (event:login_success by user_id, ip_address)
| where failures > 5
window: 15m
severity: critical

# Login from new country
- name: impossible_travel
query: |
event:login_success
| geoip(ip_address)
| stats distinct_count(country) as countries by user_id
| where countries > 1
window: 1h
severity: high

Privilege-Escalation

# Admin user created
- name: admin_user_created
query: |
event:user_created AND role:admin
severity: high

# Privilege escalation
- name: privilege_escalation
query: |
event:role_changed AND new_role:(admin OR superuser)
severity: high

# Service account used interactively
- name: service_account_interactive
query: |
event:login_success
AND user_type:service_account
AND session_type:interactive
severity: critical

Datenexfiltration

# Large data export
- name: large_data_export
query: |
event:data_export
| stats sum(record_count) as total by user_id
| where total > 10000
window: 1h
severity: high

# Database query spike
- name: unusual_database_queries
query: |
source:database
| stats count() as queries by user_id
| where queries > baseline_queries * 3
window: 1h
severity: medium

# After hours access to sensitive data
- name: after_hours_sensitive_access
query: |
event:data_access
AND data_classification:confidential
AND NOT between(hour, 8, 18)
severity: high

Infrastrukturangriffe

# SSH from unusual source
- name: ssh_from_internet
query: |
event:ssh_session_start
AND NOT source_ip:("10.*" OR "172.16.*" OR "192.168.*")
severity: high

# Cryptominer signatures
- name: cryptominer_detection
query: |
(process_name:*miner* OR cmdline:*stratum* OR cmdline:*xmrig*)
severity: critical

# Firewall rule change
- name: firewall_modified
query: |
event:(security_group_modified OR firewall_rule_changed)
severity: high

# Root/admin shell spawned
- name: root_shell_spawned
query: |
event:process_start AND user:root AND process:(bash OR sh OR zsh)
severity: medium

Warn-Ermüdung reduzieren

Zu viele Warnungen = ignorierte Warnungen. So bleiben Warnungen bedeutsam:

Geeignete Schwellenwerte setzen:

# BAD: Alerts on every failed login
- condition: event == "login_failed"

# GOOD: Alerts on suspicious patterns
- condition: count(event == "login_failed") > 10 in 5m grouped by ip_address

Kontext hinzufügen:

# BAD: Just says "suspicious activity"
message: "Suspicious activity detected"

# GOOD: Actionable information
message: |
Brute force attack detected
Source IP: {{ ip_address }}
Target users: {{ affected_users }}
Failed attempts: {{ count }}
Timeframe: last 5 minutes
Action: Consider blocking IP in WAF

Schweregrade korrekt verwenden:

  • KRITISCH: Jemand muss aufwachen
  • HOCH: Innerhalb von Stunden untersuchen
  • MITTEL: Während der Geschäftszeiten prüfen
  • NIEDRIG: Wöchentliche Überprüfung

Basierend auf Feedback anpassen:

  • Falsch-Positiv-Rate verfolgen
  • Wenn > 50 % Falsch-Positive, Schwellenwert anpassen
  • Wenn 0 % Warnungen, werden möglicherweise Dinge verpasst

Warn-Routing

Warnungen an den richtigen Ort senden:

# alertmanager.yml
route:
receiver: default
routes:
# Critical security alerts → PagerDuty
- match:
severity: critical
category: security
receiver: pagerduty-security

# High security alerts → Slack security channel
- match:
severity: high
category: security
receiver: slack-security

# Infrastructure alerts → Slack ops channel
- match:
category: infrastructure
receiver: slack-ops

receivers:
- name: pagerduty-security
pagerduty_configs:
- service_key: YOUR_PAGERDUTY_KEY
severity: critical

- name: slack-security
slack_configs:
- api_url: https://hooks.slack.com/services/XXX
channel: '#security-alerts'

- name: slack-ops
slack_configs:
- api_url: https://hooks.slack.com/services/XXX
channel: '#ops-alerts'

SIEM-Konzepte

Security Information and Event Management (SIEM) kombiniert Protokollverwaltung mit Sicherheitsanalyse. Während vollständige SIEM-Plattformen teuer sind, können Sie SIEM-ähnliche Fähigkeiten mit Open-Source-Tools aufbauen.

Was SIEM hinzufügt

| Fähigkeit | Protokollverwaltung | SIEM | ||------------|---------------|------| | Protokollsammlung | ✓ | ✓ | | Suche und Visualisierung | ✓ | ✓ | | Quellenübergreifende Korrelation | Begrenzt | ✓ | | Bedrohungsintelligenz-Integration | Manuell | Automatisch | | Verhaltensanalyse | Nein | ✓ | | Compliance-Berichterstellung | Manuell | Eingebaut | | Fallverwaltung | Nein | ✓ | | Automatisierte Reaktion | Begrenzt | ✓ |

SIEM-ähnliche Fähigkeiten aufbauen

1. Protokollkorrelation:

Protokolle aus mehreren Quellen kombinieren, um Angriffe zu erkennen:

# Detect: SSH brute force followed by successful login, then suspicious command
correlation_rule:
name: ssh_compromise_chain
events:
- event_type: ssh_failed_login
count: ">10"
group_by: source_ip, target_host
window: 5m
save_as: brute_force

- event_type: ssh_successful_login
source_ip: $brute_force.source_ip
target_host: $brute_force.target_host
within: 10m
after: brute_force
save_as: compromise

- event_type: command_execution
host: $compromise.target_host
command: ("wget*" OR "curl*" OR "nc*")
within: 30m
after: compromise

alert:
severity: critical
message: "Likely SSH compromise: brute force from {source_ip} → successful login → suspicious commands"

2. Bedrohungsintelligenz-Integration:

IPs und Domains mit bekannten bösen Akteuren abgleichen:

# Example: Check IPs against threat intel feed
import requests

def check_ip_reputation(ip_address):
# Check against AbuseIPDB
response = requests.get(
"https://api.abuseipdb.com/api/v2/check",
headers={"Key": ABUSEIPDB_API_KEY},
params={"ipAddress": ip_address}
)
data = response.json()["data"]

if data["abuseConfidenceScore"] > 80:
return {
"malicious": True,
"score": data["abuseConfidenceScore"],
"reports": data["totalReports"],
"categories": data["usageType"]
}
return {"malicious": False}

3. User and Entity Behavior Analytics (UEBA):

Anomalien basierend auf normalem Verhalten erkennen:

# Baseline: User typically logs in 9am-6pm from US
# Alert: Same user logging in at 3am from Russia

def detect_anomalous_login(user_id, login_event):
# Get user's normal login patterns
baseline = get_user_baseline(user_id)

# Check for anomalies
anomalies = []

# Time anomaly
if not baseline.normal_hours.contains(login_event.hour):
anomalies.append({
"type": "unusual_time",
"expected": baseline.normal_hours,
"actual": login_event.hour
})

# Location anomaly
if login_event.country not in baseline.normal_countries:
anomalies.append({
"type": "new_location",
"expected": baseline.normal_countries,
"actual": login_event.country
})

# Impossible travel
if baseline.last_login:
distance = calculate_distance(
baseline.last_login.location,
login_event.location
)
time_diff = login_event.time - baseline.last_login.time
if distance / time_diff.hours > 500: # 500 km/h impossible
anomalies.append({
"type": "impossible_travel",
"distance_km": distance,
"time_hours": time_diff.hours
})

return anomalies

Kostenlose SIEM-Alternativen

ToolTypAm besten fürLink
WazuhVollständiges SIEMUmfassende Sicherheitsüberwachungwazuh.com
Security OnionNetzwerk-SicherheitsüberwachungNetzwerkfokussierte Sicherheitsecurityonion.net
OSSECHost-basiertes IDSDateiintegrität, Rootkit-Erkennungossec.net
SuricataNetzwerk-IDSNetzwerkbedrohungserkennungsuricata.io
TheHiveVorfallsreaktionFallverwaltung, Playbooksthehive-project.org

Wazuh-Setup (Docker):

# docker-compose.yml for Wazuh
version: '3.8'
services:
wazuh.manager:
image: wazuh/wazuh-manager:4.7.2
hostname: wazuh.manager
ports:
- "1514:1514"
- "1515:1515"
- "514:514/udp"
- "55000:55000"
environment:
- INDEXER_URL=https://wazuh.indexer:9200
- FILEBEAT_SSL_VERIFICATION_MODE=none
volumes:
- wazuh_api_configuration:/var/ossec/api/configuration
- wazuh_etc:/var/ossec/etc
- wazuh_logs:/var/ossec/logs

wazuh.indexer:
image: wazuh/wazuh-indexer:4.7.2
hostname: wazuh.indexer
environment:
- "OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g"
volumes:
- wazuh-indexer-data:/var/lib/wazuh-indexer

wazuh.dashboard:
image: wazuh/wazuh-dashboard:4.7.2
hostname: wazuh.dashboard
ports:
- "443:5601"
environment:
- INDEXER_USERNAME=admin
- INDEXER_PASSWORD=SecretPassword
- WAZUH_API_URL=https://wazuh.manager
depends_on:
- wazuh.indexer
- wazuh.manager

volumes:
wazuh_api_configuration:
wazuh_etc:
wazuh_logs:
wazuh-indexer-data:

Wazuh bietet:

  • Dateiintegritäts-Überwachung
  • Rootkit-Erkennung
  • Protokollanalyse
  • Compliance-Dashboards (PCI-DSS, GDPR, HIPAA)
  • Aktive Reaktion (automatisches Blockieren)
  • Schwachstellen-Erkennung

Protokollaufbewahrung und Compliance

Aufbewahrungsanforderungen

| Standard | Mindestaufbewahrung | Hinweise | ||----------|------------------|-------| | PCI-DSS | 1 Jahr | 3 Monate sofort verfügbar | | HIPAA | 6 Jahre | Kann je nach Bundesstaat variieren | | SOC 2 | 1 Jahr | Abhängig von Vertrauenskriterien | | DSGVO | Variiert | „Nicht länger als notwendig" | | ISO 27001 | 3 Jahre empfohlen | Solange für Sicherheit benötigt | | Interne Best Practice | 90 Tage heiß, 1 Jahr kalt | Balance zwischen Kosten und Nützlichkeit |

Speicher-Ebenen

| Ebene | Aufbewahrung | Abfragegeschwindigkeit | Kosten | Indizierung | Beispiel | ||------|-----------|-------------|------|----------|---------| | Heiß | 7–30 Tage | Schnell | Hoch | Vollständig | Elasticsearch auf SSD | | Warm | 30–90 Tage | Langsamer | Moderat | Reduziert | Elasticsearch auf HDD, S3 + Athena | | Kalt | 90+ Tage | Nur Archiv | Niedrig | Keine | S3 Glacier, komprimierte Dateien |

Elasticsearch Index Lifecycle Management:

PUT _ilm/policy/security-logs-policy
{
"policy": {
"phases": {
"hot": {
"min_age": "0ms",
"actions": {
"rollover": {
"max_primary_shard_size": "50gb",
"max_age": "7d"
}
}
},
"warm": {
"min_age": "7d",
"actions": {
"shrink": { "number_of_shards": 1 },
"forcemerge": { "max_num_segments": 1 },
"allocate": { "require": { "data": "warm" } }
}
},
"cold": {
"min_age": "30d",
"actions": {
"allocate": { "require": { "data": "cold" } }
}
},
"delete": {
"min_age": "365d",
"actions": { "delete": {} }
}
}
}
}

Protokollintegrität

Für Compliance und Forensik müssen Protokolle manipulationssicher sein:

Protokoll-Signierung:

import hashlib
import hmac

def sign_log_entry(entry, secret_key):
"""Sign a log entry to detect tampering"""
entry_bytes = json.dumps(entry, sort_keys=True).encode()
signature = hmac.new(
secret_key.encode(),
entry_bytes,
hashlib.sha256
).hexdigest()
entry["_signature"] = signature
return entry

def verify_log_entry(entry, secret_key):
"""Verify a log entry hasn't been tampered with"""
signature = entry.pop("_signature", None)
if not signature:
return False
entry_bytes = json.dumps(entry, sort_keys=True).encode()
expected = hmac.new(
secret_key.encode(),
entry_bytes,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)

AWS CloudWatch-Protokollintegrität:

# Enable log file validation for CloudTrail
aws cloudtrail update-trail \
--name main-trail \
--enable-log-file-validation

# Validate log file integrity
aws cloudtrail validate-logs \
--trail-arn arn:aws:cloudtrail:us-east-1:123456789:trail/main-trail \
--start-time 2024-01-01T00:00:00Z

Vorfalluntersuchung mit Protokollen

Wenn ein Vorfall auftritt, sind Protokolle Ihr primäres Untersuchungswerkzeug.

Untersuchungs-Workflow

┌──────────────────┐
│ Alarm erhalten │
└────────┬─────────┘


┌──────────────────┐
│ Erste Triage │ Was hat ausgelöst? Wann? Welche Systeme?
└────────┬─────────┘


┌──────────────────┐
│ Umfangsbewertung│ Wie weit verbreitet? Welche Daten? Welcher Zugriff?
└────────┬─────────┘


┌──────────────────┐
│ Zeitachse aufb. │ Was passierte zuerst? Was kam danach?
└────────┬─────────┘


┌──────────────────┐
│ Grundursache │ Wie kamen sie rein? Was war die Schwachstelle?
└────────┬─────────┘


┌──────────────────┐
│ Auswirkungs- │ Auf was wurde zugegriffen? Was wurde geändert?
│ analyse │
└────────┬─────────┘


┌──────────────────┐
│ Eindämmung │ Blutung stoppen, Beweise sichern
└────────┬─────────┘


┌──────────────────┐
│ Dokumentation │ Zeitachse, Befunde, Erkenntnisse
└──────────────────┘

Untersuchungsabfragen

Ersten Zugriff finden:

# Kibana Query Language (KQL)
# All authentication events for compromised user around incident time
user_id: "compromised_user" AND event: (login* OR auth*)
AND @timestamp >= "2024-01-15T00:00:00" AND @timestamp <= "2024-01-15T23:59:59"
|| sort @timestamp

# Loki LogQL
{job="app"} | json | user_id="compromised_user" | line_format "{{.timestamp}} {{.event}} {{.ip_address}}"

Angreifer-Bewegung verfolgen:

# All events from attacker's IP
ip_address: "1.2.3.4" | sort @timestamp

# All events from compromised session
session_id: "abc123" | sort @timestamp

# Commands executed on compromised host
host: "compromised-server" AND event: "command_execution" | sort @timestamp

Datenzugriff identifizieren:

# Data accessed by compromised account
user_id: "compromised_user" AND event: (data_access OR data_export OR file_download)

# Unusual queries against database
source: database AND query_type: SELECT AND tables: (users OR payments OR credentials)

Zeitachse aufbauen:

def build_incident_timeline(start_time, end_time, indicators):
"""
Build timeline from logs using IOCs
indicators = {
"ip_addresses": ["1.2.3.4"],
"user_ids": ["compromised_user"],
"session_ids": ["abc123"],
"hosts": ["compromised-server"]
}
"""
timeline = []

# Query each indicator type
for ip in indicators.get("ip_addresses", []):
events = query_logs(f"ip_address:{ip}", start_time, end_time)
timeline.extend(events)

for user_id in indicators.get("user_ids", []):
events = query_logs(f"user_id:{user_id}", start_time, end_time)
timeline.extend(events)

# Deduplicate and sort
timeline = sorted(set(timeline), key=lambda e: e.timestamp)

return timeline

Untersuchungs-Checkliste

## Incident Investigation Checklist

### Initial Response
- [ ] Document alert details (time, type, affected systems)
- [ ] Assign incident owner
- [ ] Open incident ticket
- [ ] Notify relevant stakeholders

### Scoping
- [ ] Identify all affected user accounts
- [ ] Identify all affected systems/hosts
- [ ] Identify all IP addresses involved
- [ ] Determine time range of activity

### Evidence Collection
- [ ] Export relevant logs (preserve originals)
- [ ] Capture network traffic if ongoing
- [ ] Take memory dumps if needed
- [ ] Screenshot any relevant dashboards

### Analysis
- [ ] Build timeline of events
- [ ] Identify initial access vector
- [ ] Map lateral movement
- [ ] Identify data accessed/exfiltrated
- [ ] Identify persistence mechanisms

### Containment
- [ ] Block malicious IPs
- [ ] Disable compromised accounts
- [ ] Isolate compromised systems
- [ ] Revoke compromised credentials

### Documentation
- [ ] Write incident summary
- [ ] Create detailed timeline
- [ ] Document root cause
- [ ] List remediation actions
- [ ] Schedule post-mortem

Häufige Fehler

Nur Fehler protokollieren. Normaler Betrieb ist für die Sicherheit wichtig. Sie brauchen erfolgreiche Logins, um kompromittierte Konten zu erkennen, erfolgreiche API-Aufrufe, um Datenexfiltration zu erkennen. INFO-Level-Ereignisse protokollieren.

Kein Zeitstempel oder falscher Zeitzone. Protokolle ohne Zeitstempel sind für Untersuchungen nutzlos. Überall ISO 8601-Format mit UTC-Zeitzone verwenden.

Sensible Daten protokollieren. Passwörter, Token, Kreditkarten in Protokollen schaffen eine neue Schwachstelle. Sensible Felder maskieren oder ausschließen.

Keine Protokoll-Rotation. Festplatten füllen sich, Anwendungen stürzen ab. Rotation und Aufbewahrung von Tag eins an einrichten.

Warnungen ohne Runbooks. Um 3 Uhr nachts geht eine Warnung ein. Was soll die Person im Bereitschaftsdienst tun? Reaktionsverfahren für jeden Warnungstyp dokumentieren.

Zu viele Warnungen. Warn-Ermüdung tötet die Sicherheit. Wenn Sie Warnungen ignorieren, überwachen Sie nicht. Schwellenwerte abstimmen und Rauschen unterdrücken.

Protokolle nur auf Anwendungsservern. Sicherheitsereignisse passieren überall — Firewalls, Datenbanken, Cloud-APIs, Load Balancer. Alle sammeln.

Kein Testen. Wie wissen Sie, dass Ihre Warnungen funktionieren? Testereignisse generieren, prüfen ob sie ausgelöst werden, prüfen ob das Routing stimmt.

Reale Vorfälle

Target-Datenpanne (2013): Angreifer waren wochenlang im Netzwerk. Sicherheits-Tools generierten Warnungen über die Malware, aber sie wurden wegen Warn-Ermüdung ignoriert. 40 Millionen Kreditkarten gestohlen. Quelle: U.S. Senate Committee

Equifax-Datenpanne (2017): Angriff begann im Mai, wurde im Juli entdeckt. Schlechte Protokollierung bedeutete, dass Ermittler das volle Ausmaß der Datenpanne nicht bestimmen konnten. 147 Millionen Datensätze exponiert. Die Untersuchung dauerte Monate, weil Protokolldaten unvollständig waren. Quelle: GAO-Bericht

SolarWinds (2020): Angreifer waren 9+ Monate in Netzwerken, bevor sie entdeckt wurden. Unternehmen mit besserer Protokollierung und Anomalieerkennung konnten ungewöhnliches Verhalten der kompromittierten Software-Updates identifizieren. Quelle: CISA

Colonial Pipeline (2021): Angreifer griffen über ein kompromittiertes VPN-Passwort auf das Netzwerk zu. Ordentliche Überwachung von VPN-Authentifizierungsmustern hätte den unbefugten Zugriff früher erkennen können. Quelle: Bloomberg

Workshop: Protokollierung und Überwachung einrichten

Dieser Workshop führt Sie durch die Implementierung einer vollständigen Protokollierungs- und Überwachungslösung.

Teil 1: Zentralisierte Protokollsammlung

Option A: Grafana Loki (empfohlen für kleine Teams)

  1. docker-compose.yml erstellen:
version: '3.8'
services:
loki:
image: grafana/loki:2.9.3
ports:
- "3100:3100"
command: -config.file=/etc/loki/local-config.yaml
volumes:
- loki-data:/loki

grafana:
image: grafana/grafana:10.3.1
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
- GF_AUTH_ANONYMOUS_ENABLED=true
volumes:
- grafana-data:/var/lib/grafana
- ./grafana/provisioning:/etc/grafana/provisioning

promtail:
image: grafana/promtail:2.9.3
volumes:
- ./promtail-config.yaml:/etc/promtail/config.yml
- /var/log:/var/log:ro
- /var/run/docker.sock:/var/run/docker.sock
command: -config.file=/etc/promtail/config.yml

volumes:
loki-data:
grafana-data:
  1. promtail-config.yaml erstellen:
server:
http_listen_port: 9080

positions:
filename: /tmp/positions.yaml

clients:
- url: http://loki:3100/loki/api/v1/push

scrape_configs:
- job_name: system
static_configs:
- targets:
- localhost
labels:
job: varlogs
host: ${HOSTNAME}
__path__: /var/log/*.log

- job_name: docker
docker_sd_configs:
- host: unix:///var/run/docker.sock
refresh_interval: 5s
relabel_configs:
- source_labels: ['__meta_docker_container_name']
target_label: container
  1. Stack starten:
docker compose up -d
  1. Grafana unter http://localhost:3000 aufrufen

  2. Loki als Datenquelle hinzufügen:

    • Zu Connections → Data Sources → Add data source gehen
    • Loki auswählen
    • URL: http://loki:3100
    • Save & Test

Option B: AWS CloudWatch (für AWS-Umgebungen)

  1. CloudWatch-Agent installieren:
wget https://s3.amazonaws.com/amazoncloudwatch-agent/ubuntu/amd64/latest/amazon-cloudwatch-agent.deb
sudo dpkg -i amazon-cloudwatch-agent.deb
  1. Konfiguration erstellen:
{
"logs": {
"logs_collected": {
"files": {
"collect_list": [
{
"file_path": "/var/log/auth.log",
"log_group_name": "security-logs",
"log_stream_name": "{instance_id}/auth"
},
{
"file_path": "/var/log/nginx/access.log",
"log_group_name": "application-logs",
"log_stream_name": "{instance_id}/nginx-access"
},
{
"file_path": "/app/logs/*.json",
"log_group_name": "application-logs",
"log_stream_name": "{instance_id}/app"
}
]
}
}
}
}
  1. Agent starten:
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl \
-a fetch-config \
-m ec2 \
-s \
-c file:/opt/aws/amazon-cloudwatch-agent/etc/config.json

Teil 2: Anwendungs-Protokollierung

  1. Strukturierte Protokollierung zu Ihrer Anwendung hinzufügen:

Python-Beispiel:

import structlog
import logging

# Configure structlog
structlog.configure(
processors=[
structlog.stdlib.filter_by_level,
structlog.stdlib.add_logger_name,
structlog.stdlib.add_log_level,
structlog.processors.TimeStamper(fmt="iso"),
structlog.processors.JSONRenderer()
],
wrapper_class=structlog.stdlib.BoundLogger,
context_class=dict,
logger_factory=structlog.stdlib.LoggerFactory(),
)

logger = structlog.get_logger()

# Log security events
def login(user_id, ip_address, success):
logger.info(
"user_login",
user_id=user_id,
ip_address=ip_address,
success=success,
event_type="authentication"
)

Node.js-Beispiel:

const pino = require('pino');

const logger = pino({
level: 'info',
formatters: {
level: (label) => ({ level: label }),
},
timestamp: pino.stdTimeFunctions.isoTime,
});

// Log security events
function login(userId, ipAddress, success) {
logger.info({
event: 'user_login',
user_id: userId,
ip_address: ipAddress,
success: success,
event_type: 'authentication'
});
}
  1. Protokollierung testen:
# Generate some log entries
curl -X POST http://localhost:8000/api/login \
-H "Content-Type: application/json" \
-d '{"username": "test", "password": "wrong"}'

# Check logs appear in Grafana/CloudWatch

Teil 3: Sicherheitswarnungen

  1. Warnung für fehlgeschlagene Logins erstellen (Grafana):

    • Zu Alerting → Alert rules → New alert rule gehen
    • Abfrage: count_over_time({job="app"} |= "login" |= "success\":false" [5m])
    • Bedingung: Is above 10
    • Ordner: Security
    • Auswertung: Alle 1m für 5m
    • Benachrichtigungskanal hinzufügen (Slack, E-Mail usw.)
  2. CloudWatch-Alarm erstellen:

# Create metric filter
aws logs put-metric-filter \
--log-group-name application-logs \
--filter-name failed-logins \
--filter-pattern '{ $.event = "user_login" && $.success = false }' \
--metric-transformations \
metricName=FailedLogins,metricNamespace=Security,metricValue=1

# Create alarm
aws cloudwatch put-metric-alarm \
--alarm-name HighFailedLogins \
--metric-name FailedLogins \
--namespace Security \
--statistic Sum \
--period 300 \
--threshold 20 \
--comparison-operator GreaterThanThreshold \
--evaluation-periods 1 \
--alarm-actions arn:aws:sns:us-east-1:123456789:security-alerts
  1. Warnungen testen:
# Generate failed logins
for i in {1..25}; do
curl -X POST http://localhost:8000/api/login \
-H "Content-Type: application/json" \
-d '{"username": "test", "password": "wrong"}'
sleep 1
done

# Verify alert fired

Teil 4: Sicherheits-Dashboard

Ein Grafana-Dashboard mit diesen Panels erstellen:

  1. Authentifizierungsübersicht:

    • Gesamte Logins (Erfolg/Fehlschlag)
    • Login-Fehlschlagsrate im Zeitverlauf
    • Top-Quell-IPs für Fehlschläge
  2. Anwendungssicherheit:

    • Fehlerraten
    • API-Antwortzeiten
    • Rate-Limit-Treffer
  3. Infrastruktur:

    • SSH-Verbindungen
    • Sudo-Befehle
    • Dienststatus-Änderungen

Beispiel-Dashboard-JSON:

{
"title": "Security Overview",
"panels": [
{
"title": "Failed Logins (24h)",
"type": "stat",
"targets": [
{
"expr": "count_over_time({job=\"app\"} |= \"login\" |= \"success\\\":false\" [24h])"
}
]
},
{
"title": "Login Failures by IP",
"type": "table",
"targets": [
{
"expr": "sum by (ip_address) (count_over_time({job=\"app\"} |= \"login\" |= \"success\\\":false\" [24h]))"
}
]
},
{
"title": "Authentication Events",
"type": "timeseries",
"targets": [
{
"expr": "sum(count_over_time({job=\"app\"} |= \"login\" [5m]))",
"legendFormat": "Total"
},
{
"expr": "sum(count_over_time({job=\"app\"} |= \"login\" |= \"success\\\":false\" [5m]))",
"legendFormat": "Failed"
}
]
}
]
}

Zu produzierende Ergebnisse

Nach diesem Workshop sollten Sie haben:

  1. Zentralisierter Protokollierungs-Stack — Docker-Compose- oder CloudWatch-Konfiguration
  2. Anwendungs-Protokollierungs-Integration — Strukturierte Protokollierung in Ihrem Code
  3. Sicherheitswarnungen — Mindestens 3 konfigurierte Warnungen:
    • Schwellenwert für fehlgeschlagene Logins
    • Zugriff außerhalb der Geschäftszeiten
    • Fehlerrate-Spitze
  4. Sicherheits-Dashboard — Grafana/CloudWatch-Dashboard mit wichtigen Metriken
  5. Warn-Runbook — Dokumentation zur Reaktion auf jeden Warnungstyp
  6. Protokollaufbewahrungsrichtlinie — Dokument, wie lange Protokolle aufbewahrt werden und warum

Selbstprüfungs-Fragen

  1. Warum ist zentralisierte Protokollierung für die Sicherheit wichtig?
  2. Was sollte niemals protokolliert werden?
  3. Was ist der Unterschied zwischen einem Protokollverwaltungssystem und einem SIEM?
  4. Wie verhindern Sie Warn-Ermüdung?
  5. Welche Protokollaufbewahrungsdauer erfordert PCI-DSS?
  6. Wie würden Sie eine vermutete Kontoübernahme anhand von Protokollen untersuchen?
  7. Was ist strukturierte Protokollierung und warum ist sie besser?
  8. Wie stellen Sie die Protokollintegrität für forensische Zwecke sicher?
  9. Nennen Sie drei Sicherheitsereignisse, die sofortige Warnungen auslösen sollten.
  10. Was ist der Unterschied zwischen heißem, warmem und kaltem Protokollspeicher?

Gespräch mit der Führungsebene

Mit dem Risiko beginnen: „Im Moment, wenn jemand unser System durchbricht, werden wir es monatelang nicht wissen. Ein durchschnittliches Unternehmen braucht 194 Tage, um eine Datenpanne zu erkennen. Mit ordentlicher Überwachung können wir Probleme in Minuten erkennen."

Ein reales Beispiel verwenden: „Letzten Monat hatte [Wettbewerber/Nachrichtenmeldung] eine Datenpanne. Sie konnten nicht herausfinden, welche Daten gestohlen wurden, weil ihre Protokolle unvollständig waren. Wir richten Protokollierung ein, damit wir diese Frage immer beantworten können."

Den Wert quantifizieren: „Schnellere Erkennung bedeutet weniger Schaden. Laut IBM kosten Datenpannen, die innerhalb von 200 Tagen erkannt werden, 1 Million Dollar weniger als solche, die länger dauern. Unsere Überwachung warnt uns sofort."

Compliance ansprechen: „Für SOC 2 / ISO 27001 / [relevanter Standard] brauchen wir zentralisierte Protokollierung mit ordnungsgemäßer Aufbewahrung. Dieses Projekt bringt uns in Compliance."

Das Dashboard zeigen: „Hier ist, was wir jetzt überwachen. Wir können jeden Login, jeden Zugriff auf sensible Daten, jedes ungewöhnliche Muster sehen. Vorher waren wir blind."

Kosten vergleichen: „Wir verwenden Open-Source-Tools, die 0 € an Software-Lizenzen kosten. Die Hauptkosten sind meine Zeit für die Einrichtung — etwa 2 Wochen. Ein SIEM-Produkt würde 50.000–100.000 €/Jahr kosten."

Protokollverwaltung

Cloud-Protokollierung

SIEM und Sicherheitsüberwachung

Best Practices

Alarmierung und Vorfallsreaktion

Was kommt als Nächstes

Damit ist der Abschnitt zur Sicherheit in der Entwicklung abgeschlossen. Sie können jetzt sichereren Code schreiben, Geheimnisse ordnungsgemäß verwalten, Ihre CI/CD-Pipeline härten, Container und Cloud-Infrastruktur absichern und verdächtige Aktivitäten erkennen, wenn sie auftreten.

Nächster Abschnitt: Sicherheitskultur — die schwierigere Arbeit, alle anderen im Team dazu zu bringen, sich um Sicherheit zu kümmern.