Secure Coding Practices: Sicherheit im Entwicklungsprozess verankern
Secure Coding und Secure SDLC: Von Threat Modeling und STRIDE über sprachspezifische Sicherheitsmuster (Python, Java, Node.js, Go) für Input Validation, SQL Injection, Authentifizierung und Kryptographie bis zu SAST/DAST/SCA in CI/CD, Security Code Reviews, Container Security, SBOM, Secrets Management und dem OWASP SAMM Reifegradmodell. Praxisleitfaden für Entwicklungsteams ohne eigene Security-Abteilung.
Inhaltsverzeichnis (14 Abschnitte)
Sicherheitslücken entstehen meist nicht durch fehlende Absicht, sondern durch fehlende Gewohnheiten. Secure Coding bedeutet, die richtigen Muster zu verinnerlichen bis sie zur Selbstverständlichkeit werden. Sicherheit im SDLC nachträglich einzubauen ist wie Sicherheitsgurte nach dem Unfall anzulegen: teuer, ineffektiv und zu spät. Ein Bug im Design kostet rund 100 EUR, im Code 1.000 EUR und in Produktion 100.000 EUR oder mehr.
Der Secure SDLC (Software Development Lifecycle)
Traditioneller SDLC:
Requirements → Design → Coding → Testing → Deployment → Maintenance
↑
Security-Test erst hier!
Secure SDLC (Microsoft SDL / OWASP SDLC):
Requirements → Sicherheitsanforderungen definieren
Design → Threat Modeling (STRIDE/PASTA)
Coding → Secure Coding Guidelines, SAST im IDE
Testing → DAST, Penetrationstest, SCA
Deployment → Security-Review, Secure Config
Maintenance → Patch-Management, Vulnerability Monitoring
Grundprinzipien Secure Coding
Die zehn wichtigsten Secure-Coding-Prinzipien:
1. Input Validation (Alle Eingaben sind verdächtig):
→ Validiere ALLES: HTTP-Parameter, Headers, Cookies, Dateiinhalte
→ Whitelist-basiert: was ERLAUBT ist, nicht was verboten
→ Validierung: so früh wie möglich, so nah an der Eingabe wie möglich
2. Output Encoding (Kontext-abhängig):
→ HTML-Context: HTML-Entity-Encoding (< → <)
→ JavaScript-Context: JavaScript-Encoding (\x3C)
→ SQL-Context: Parameterized Queries (nie String-Konkatenation!)
→ URL-Context: URL-Encoding (%3C)
→ Falscher Kontext = XSS, Injection!
3. Authentication (Identität verifizieren):
→ Starke Passwort-Hashing-Algorithmen (bcrypt, Argon2, PBKDF2)
→ MFA für privilegierte Aktionen
→ Session-Management: zufällige Session-IDs, kurze Lifetime
4. Authorization (Zugriff kontrollieren):
→ Object-Level Authorization für jede Ressource
→ Least Privilege: minimale Berechtigungen
→ Deny-by-default: was nicht explizit erlaubt ist, ist verboten
5. Fail Secure (Bei Fehler: Zugang verweigern):
→ Exception = Zugang verwehren, nicht gewähren
→ Keine Default-Credentials
→ Sichere Defaults überall
6. Separation of Concerns:
→ Daten und Code strikt trennen (SQL, HTML, Shell)
→ Template-Engines: User-Input als Variablen, nie in Templates
7. Defense in Depth:
→ Mehrere unabhängige Sicherheitsschichten
→ Eine Schwachstelle kompromittiert nicht alles
8. Cryptography: Nur geprüfte Bibliotheken:
→ NIEMALS eigene Krypto implementieren!
→ Sichere Defaults: AES-256-GCM, RSA-4096 oder Ed25519, bcrypt
9. Error Handling: Keine sensitiven Details:
→ Interne Fehler loggen, aber nicht ans Frontend weitergeben
→ Generic error messages für Angreifer, Correlation-ID für Support
10. Logging und Monitoring:
→ Security-relevante Ereignisse loggen (Logins, Zugriffsversuche)
→ Keine sensitiven Daten in Logs (Passwörter, Tokens, PII)
Phase 1: Security Requirements und Design
OWASP Application Security Verification Standard (ASVS):
Level 1: Grundlegende Sicherheit (alle Anwendungen)
Level 2: Standard-Sicherheit (business-critical)
Level 3: Höchste Sicherheit (kritische Infrastruktur)
Wichtigste ASVS-Anforderungen (Level 1):
V1: Architektur, Design und Bedrohungsmodell
V2: Authentifizierung (MFA, Session Management)
V3: Session Management (sichere Tokens, Timeout)
V5: Input Validation und Encoding (XSS, SQLi verhindern)
V6: Kryptographie (AES-256, TLS 1.2+, kein MD5!)
V8: Datenschutz (Logging, Fehlerbehandlung ohne Datenleck)
V9: Kommunikationssicherheit (TLS, Certificate Pinning)
V14: Konfigurationssicherheit (Secrets, Dependencies)
Threat Modeling mit STRIDE
STRIDE-Bedrohungsmodell - pro Komponente analysieren:
Datenflussdiagramm (DFD):
Externe Nutzer
│
▼
[Browser] ──HTTPS──► [Web-App-Server] ──► [DB-Server]
│
└──► [Auth-Service]
Vertrauensgrenzen (Trust Boundaries):
Internet → DMZ → Intranet → Datenbank
STRIDE pro Komponente (Beispiel Web-App-Server):
S (Spoofing - Identitätsfälschung):
→ Frage: Kann ein Angreifer als jemand anderes auftreten?
→ Gegenmittel: MFA, starke Authentifizierung, JWT-Signierung
T (Tampering - Manipulation):
→ Frage: Kann ein Angreifer Daten ändern?
→ Gegenmittel: Signaturen, MAC, Input Validation, HMAC
R (Repudiation - Abstreitbarkeit):
→ Frage: Kann jemand Aktionen abstreiten?
→ Gegenmittel: unveränderliche Audit-Logs, digitale Signaturen
I (Information Disclosure - Datenleck):
→ Frage: Werden sensible Daten unbeabsichtigt preisgegeben?
→ Gegenmittel: Error Handling, Verschlüsselung, Minimal Disclosure
D (Denial of Service - Verfügbarkeit):
→ Frage: Kann der Dienst zum Absturz gebracht werden?
→ Gegenmittel: Rate Limiting, Input Size Limits, Circuit Breaker
E (Elevation of Privilege - Rechteeskalation):
→ Frage: Kann ein Nutzer mehr Rechte erlangen als erlaubt?
→ Gegenmittel: Least Privilege, RBAC, IDOR-Schutz
Security Story Template:
"Als [Angreifer] will ich [Angriffsaktion] um [Ziel] zu erreichen."
Beispiel: "Als Angreifer will ich durch SQL-Injection die Kundendatenbank
auslesen, um Kreditkartendaten zu stehlen."
→ Jede Security Story: entsprechende Test Case definieren
Input Validation Patterns
Richtige Input-Validierung (mehrere Sprachen):
Python (allgemein):
import re, html
from email_validator import validate_email, EmailNotValidError
def validate_username(username: str) -> str:
if not isinstance(username, str):
raise ValueError("Username muss String sein")
if not 3 <= len(username) <= 50:
raise ValueError("Username: 3-50 Zeichen")
if not re.match(r'^[a-zA-Z0-9_-]+$', username):
raise ValueError("Nur Buchstaben, Zahlen, _ und -")
return username
safe_output = html.escape(user_input) # HTML-Ausgabe sicher escapen
try:
valid = validate_email(email, check_deliverability=False)
safe_email = valid.email
except EmailNotValidError:
raise ValueError("Ungültige E-Mail")
Java (Spring Bean Validation - JSR-380):
public class UserRequest {
@NotBlank @Size(min=3, max=50)
@Pattern(regexp = "^[a-zA-Z0-9_-]+$",
message = "Nur erlaubte Zeichen")
private String username;
@Email @NotBlank
private String email;
@Min(0) @Max(150)
private Integer age;
}
Node.js (Zod):
import { z } from 'zod';
const UserSchema = z.object({
username: z.string()
.min(3).max(50)
.regex(/^[a-zA-Z0-9_-]+$/),
email: z.string().email(),
age: z.number().int().min(0).max(150).optional()
});
const result = UserSchema.safeParse(req.body);
if (!result.success) {
return res.status(400).json(result.error.flatten());
}
Datei-Upload-Validierung:
ALLOWED_MIME_TYPES = {'image/jpeg', 'image/png', 'image/webp'}
MAX_SIZE_BYTES = 5 * 1024 * 1024 # 5MB
import magic # python-magic liest MagicBytes, nicht nur Extension!
mime = magic.from_buffer(file.read(1024), mime=True)
if mime not in ALLOWED_MIME_TYPES:
raise ValueError(f"Unerlaubter Dateityp: {mime}")
# MagicBytes prüfen, NICHT den Dateinamen!
# upload.jpg.php → MagicBytes = PHP → geblockt!
Path Traversal verhindern:
import os
def safe_join(base, user_path):
path = os.path.realpath(os.path.join(base, user_path))
if not path.startswith(base):
raise ValueError("Path traversal attempt detected!")
return path
SQL Injection Prevention
Sichere Datenbankabfragen - das Grundprinzip:
Python (sqlite3/psycopg2):
# FALSCH - SQL Injection möglich:
query = f"SELECT * FROM users WHERE username='{username}'"
cursor.execute(query)
# RICHTIG - Parameterized Query:
cursor.execute(
"SELECT * FROM users WHERE username = %s",
(username,)
)
# SQLAlchemy ORM (noch sicherer):
user = db.session.query(User).filter_by(username=username).first()
Java (PreparedStatement):
// FALSCH:
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(
"SELECT * FROM users WHERE id=" + userId);
// RICHTIG:
PreparedStatement ps = conn.prepareStatement(
"SELECT * FROM users WHERE id = ?");
ps.setInt(1, userId);
ResultSet rs = ps.executeQuery();
Node.js (pg):
// FALSCH:
const result = await pool.query(
`SELECT * FROM orders WHERE user_id='${userId}'`);
// RICHTIG:
const result = await pool.query(
'SELECT * FROM orders WHERE user_id = $1',
[userId]
);
// Prisma ORM (sicher by design):
const user = await prisma.user.findUnique({
where: { id: userId }
});
NoSQL Injection (MongoDB):
// FALSCH:
db.users.find({ username: req.body.username })
// Wenn username = { $gt: "" } → alle User!
// RICHTIG - Type-Check:
if (typeof req.body.username !== 'string') {
return res.status(400).send('Invalid input');
}
// NIEMALS: db.users.find({ $where: "this.field..." })
Authentifizierung und Session Management
Sichere Passwort-Verwaltung:
Algorithmen:
RICHTIG: bcrypt (weit verbreitet, solide), Argon2id (aktuellster Standard)
scrypt (memory-hard), PBKDF2 (FIPS-Konformität)
FALSCH: MD5, SHA-1, SHA-256 allein!
Ohne Salt: Rainbow-Table-Angriffe möglich!
Zu schnell: Brute-Force in Sekunden!
Python (Argon2id):
from argon2 import PasswordHasher
ph = PasswordHasher(time_cost=3, memory_cost=65536, parallelism=2)
hash = ph.hash("user-password")
try:
ph.verify(hash, "user-password")
if ph.check_needs_rehash(hash):
hash = ph.hash("user-password") # Upgrade bei neuen Params
except VerifyMismatchError:
raise ValueError("Falsches Passwort")
Node.js (bcrypt):
const bcrypt = require('bcrypt');
const ROUNDS = 12;
const hash = await bcrypt.hash(password, ROUNDS);
const valid = await bcrypt.compare(password, hash);
Java (BCryptPasswordEncoder):
PasswordEncoder encoder = new BCryptPasswordEncoder(12);
String hashed = encoder.encode(rawPassword);
boolean valid = encoder.matches(rawPassword, hashed);
Session-Management:
# Session-ID: kryptografisch zufällig, mind. 128 Bit:
import secrets
session_id = secrets.token_hex(32) # 256 Bit
# Session-Cookie-Attribute:
response.set_cookie(
'session', session_id,
httponly=True, # Kein JS-Zugriff
secure=True, # Nur HTTPS
samesite='Strict', # CSRF-Schutz
max_age=3600 # 1h Lifetime
)
# Session-Rotation nach Login (Session-Fixation-Schutz!):
old_session_data = get_session(old_id)
new_id = secrets.token_hex(32)
create_session(new_id, old_session_data)
delete_session(old_id)
JWT (korrekt verwenden):
const token = jwt.sign(
{ userId: user.id, role: user.role },
process.env.JWT_SECRET, # stark, aus Env!
{ expiresIn: '1h', algorithm: 'RS256' } # asymmetrisch!
);
# NIEMALS: algorithms=["none"] oder ohne Algorithmus-Angabe!
Secrets Management
FALSCH: Hardcoded Secrets
DATABASE_URL = "postgresql://admin:SuperSecret123@db.firma.de/prod" # in Git!
RICHTIG: Environment Variables
DB_PASSWORD = os.environ.get('DB_PASSWORD')
BESSER: Secret Management System
import hvac # HashiCorp Vault
client = hvac.Client()
secret = client.secrets.kv.read_secret_version(path='my-app/db')
DB_PASSWORD = secret['data']['data']['password']
# Azure Key Vault:
from azure.keyvault.secrets import SecretClient
# AWS Secrets Manager, GCP Secret Manager analog
.gitignore: immer .env hinzufügen!
echo ".env" >> .gitignore
Pre-commit Hooks für Secret Detection:
pip install detect-secrets
detect-secrets scan > .secrets.baseline
# Gitleaks: pre-commit hook in .pre-commit-config.yaml
Kryptographie-Patterns in der Entwicklung
Sichere Kryptographie in Applikationen:
Symmetrische Verschlüsselung (AES-GCM):
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os
key = AESGCM.generate_key(bit_length=256)
aesgcm = AESGCM(key)
nonce = os.urandom(12) # 96 Bit Nonce, EINMALIG!
ciphertext = aesgcm.encrypt(nonce, plaintext, associated_data)
stored = nonce + ciphertext # Nonce mit gespeichert
nonce = stored[:12]
ciphertext = stored[12:]
plaintext = aesgcm.decrypt(nonce, ciphertext, associated_data)
# WICHTIG: Nonce niemals wiederverwenden! (GCM-Nonce-Misuse-Angriff)
Asymmetrische Signaturen (Ed25519):
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
private_key = Ed25519PrivateKey.generate()
public_key = private_key.public_key()
signature = private_key.sign(message)
public_key.verify(signature, message) # Exception wenn ungültig
Zufallszahlen für Sicherheitszwecke:
Python: secrets.token_bytes(32) # kryptografisch sicher!
Java: SecureRandom.getInstanceStrong()
Node.js: crypto.randomBytes(32)
Go: crypto/rand.Read()
NIEMALS für Security:
Python: random.random() → NICHT kryptografisch sicher!
Java: Math.random() → NICHT kryptografisch sicher!
JS: Math.random() → NICHT kryptografisch sicher!
Fehlerbehandlung und sicheres Logging
Keine internen Details ans Frontend:
FALSCH:
try:
result = database_query(user_id)
except Exception as e:
return {"error": str(e)} # DB-Struktur, Tabellennamen, SQL-Details!
RICHTIG:
import uuid
try:
result = database_query(user_id)
except DatabaseError as e:
error_id = str(uuid.uuid4())
logger.error(f"[{error_id}] DB error for user {user_id}: {e}", exc_info=True)
return {"error": "Interner Fehler", "reference": error_id}, 500
Sicheres Logging:
NIEMALS loggen:
□ Passwörter (auch falsche Logins!)
□ Session-IDs / Tokens
□ Kreditkartennummern (PCI-DSS!)
□ Private Keys
□ Vollständige PII (DSGVO!)
Maskierung sensibler Daten:
def mask_sensitive(data: dict) -> dict:
SENSITIVE_KEYS = {'password', 'token', 'credit_card', 'secret'}
return {
k: '***' if k.lower() in SENSITIVE_KEYS else v
for k, v in data.items()
}
Structured Logging (für SIEM-Integration):
import structlog
log = structlog.get_logger()
log.warning(
"failed_login",
username=username,
ip=request.remote_addr,
user_agent=request.headers.get('User-Agent'),
timestamp=datetime.utcnow().isoformat()
)
# JSON-Format → einfach in SIEM importierbar
Security Testing in CI/CD
Automatisierte Sicherheitsprüfungen:
SAST (Static Application Security Testing):
Semgrep (Open Source):
- name: Run Semgrep
uses: returntocorp/semgrep-action@v1
with:
config: >-
p/owasp-top-ten
p/python
p/javascript
p/docker
CodeQL (GitHub Actions, kostenlos für Open Source):
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: python, javascript
Was SAST findet:
→ SQL Injection-Muster
→ Hardcoded Secrets (Passwort in Code)
→ Unsichere Zufallszahlen (Math.random statt crypto.randomBytes)
→ Fehlende Input-Validierung
→ Unsichere Konfigurationen (CORS: *)
SCA (Software Composition Analysis):
Trivy (Alle-in-einem-Scanner):
trivy image myapp:latest # Container scannen
trivy fs --scanners vuln,secret,misconfig ./ # Filesystem
trivy image --format cyclonedx --output sbom.json myapp:latest # SBOM
Python SCA:
pip install pip-audit
pip-audit --vulnerability-service pypi
Node.js:
npm audit --audit-level=high
Dependabot (.github/dependabot.yml):
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
Secrets Scanning:
# Gitleaks (CI):
- name: Gitleaks Secret Scan
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Trufflehog (tieferer Scan inkl. Commit-History):
- name: TruffleHog OSS
uses: trufflesecurity/trufflehog@main
with:
extra_args: --only-verified
DAST (Dynamic Application Security Testing):
OWASP ZAP Baseline Scan in CI/CD:
- name: ZAP Baseline Scan
uses: zaproxy/action-baseline@v0.10.0
with:
target: 'https://staging.meineapp.de'
cmd_options: '-T 120'
Nuclei (Template-basiert):
nuclei -u https://staging.meinapp.de -t cves/ -t misconfigurations/
Container Security
Dockerfile Best Practices:
FALSCH:
FROM ubuntu:latest
RUN apt-get install -y python3 && pip install -r requirements.txt
USER root # niemals!
RICHTIG:
FROM python:3.12-slim # minimal image
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
# Non-root user:
RUN useradd --create-home appuser
USER appuser
# Health check:
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost:8080/health || exit 1
EXPOSE 8080
CMD ["python", "app.py"]
Dependency Pinning:
→ package-lock.json / yarn.lock / poetry.lock immer committen! (reproduzierbare Builds)
→ Regelmäßig aktualisieren (Dependabot/Renovate)
→ pip: requirements.txt mit exakten Versionen:
flask==3.0.1 # nicht flask>=3.0.0!
→ Docker: nie "latest" in Produktion:
FROM python:3.12.1-slim # spezifische Version!
Security Release Gates
Pflichtprüfungen vor Deployment:
Definition of Done (Security):
→ SAST: 0 kritische Findings (Semgrep/SonarQube)
→ SCA: 0 kritische CVEs in Dependencies (Trivy/Snyk)
→ Secrets Scan: 0 Secrets im Code (GitLeaks/detect-secrets)
→ DAST Baseline: 0 High/Critical in Staging (ZAP)
→ Security Code Review: abgenommen
GitHub Actions Security Gate:
security-gate:
runs-on: ubuntu-latest
needs: [sast, sca, secrets-scan]
steps:
- name: Check security scan results
run: |
if [ -f sast-findings.json ]; then
CRITICAL=$(jq '[.[] | select(.severity == "CRITICAL")] | length' sast-findings.json)
if [ "$CRITICAL" -gt 0 ]; then
echo "FAIL: $CRITICAL critical SAST findings!"
exit 1
fi
fi
SBOM (Software Bill of Materials):
→ ISO/IEC 5962, SPDX oder CycloneDX Format
→ Pflicht für: US-Regierungsaufträge (Executive Order 2021)
→ Empfohlen: KRITIS-Betreiber, kritische Anwendungen
→ Syft: syft myapp:latest -o cyclonedx-json > sbom.json
Security Code Review Checkliste
Quick-Reference für Code-Reviews:
Injection-Prüfung:
□ SQL: Parameterized Queries überall? (grep nach String-Konkatenation mit SQL)
□ Command Injection: Shell-Aufrufe → nur execFile mit Array-Args
□ SSTI: Template-Strings mit User-Input? (nur Variables, nie inline!)
□ XXE: XML-Parser konfiguriert? (external entities disabled)
□ LDAP-Injection: LDAP-Queries escaped?
□ NoSQL Injection: Type-Check vor MongoDB-Queries?
Authentifizierung & Session:
□ Passwort-Hashing: bcrypt/Argon2? (kein MD5, SHA-1, SHA-256 allein!)
□ Session-IDs: kryptografisch zufällig (crypto.randomBytes)?
□ Session-Rotation nach Login?
□ CSRF-Schutz auf state-changing Endpoints?
□ Session-Timeout implementiert?
□ Logout: Session serverseitig invalidiert?
Autorisierung:
□ Alle Endpoints: Authentifizierung erzwungen?
□ Jede Ressource: Ownership-Check (nicht nur Auth-Check! IDOR!)
□ RBAC/ABAC korrekt implementiert?
□ Admin-Funktionen: doppelte Prüfung?
□ Versteckte Felder/Parameter: serverseitig validiert (nicht vertrauen!)?
Kryptografie:
□ Keine selbst implementierte Krypto?
□ Starke Algorithmen: AES-256-GCM, RSA-4096/Ed25519, bcrypt/Argon2?
□ Nonce-Wiederverwendung vermieden?
□ Secrets nicht im Code (Env-Vars oder Secrets Manager)?
□ TLS: Version 1.2+ erzwungen?
Input & Output:
□ Alle User-Inputs: validiert und sanitisiert?
□ SQL: ausschließlich Parameterized Queries?
□ HTML Output: escaped (XSS-Schutz)?
□ File Uploads: Typ/Größe/Name validiert?
□ Error Messages: keine Stack Traces, keine interne Info!
Logging:
□ Keine sensiblen Daten in Logs (Passwörter, Tokens, Kreditkarten!)?
□ Sicherheitsereignisse geloggt (Login, Fehler, Rechte-Zugriff)?
□ Logs nicht manipulierbar durch User-Input (Log Injection)?
Dependencies:
□ npm audit / pip audit / mvn dependency-check ausgeführt?
□ Bekannte CVEs in Dependencies?
□ Keine veralteten Kryptobibliotheken?
□ Neue Dependencies: Sicherheits-Review durchgeführt?
Reifegrad-Modell: OWASP SAMM
OWASP SAMM (Software Assurance Maturity Model) - Reifegrade:
Level 1 (Basis):
✓ OWASP Top 10 Schulung für Entwickler
✓ Manueller Security-Review vor Release
✓ Grundlegendes SAST in IDE
✓ Security User Stories
Level 2 (Fortgeschritten):
✓ Threat Modeling für neue Features
✓ SAST + SCA in CI/CD-Pipeline
✓ DAST auf Staging-Umgebung
✓ Security Champions in Entwicklungsteams
✓ Security Release Gates
Level 3 (Führend):
✓ Kontinuierlicher Pentest (Bug Bounty)
✓ Automatisierte DAST in Production
✓ Security Architecture Reviews
✓ Red Team Exercises
✓ SBOM für alle Releases
Für die meisten deutschen KMU ist Level 1-2 realistisch und schützt
gegen 80% der häufigsten Schwachstellen. Ein Penetrationstest jährlich
deckt auf, was CI/CD-Tools übersehen. Quellen & Referenzen
- [1] OWASP Secure Coding Practices Quick Reference Guide - OWASP
- [2] OWASP Secure Development Lifecycle - OWASP
- [3] Microsoft Security Development Lifecycle - Microsoft
- [4] NIST Secure Software Development Framework (SSDF) - NIST
- [5] OWASP Application Security Verification Standard (ASVS) - OWASP
Fragen zu diesem Thema?
Unsere Experten beraten Sie kostenlos und unverbindlich.
Über den Autor
Geschäftsführender Gesellschafter der AWARE7 GmbH mit langjähriger Expertise in Informationssicherheit, Penetrationstesting und IT-Risikomanagement. Absolvent des Masterstudiengangs Internet-Sicherheit an der Westfälischen Hochschule (if(is), Prof. Norbert Pohlmann). Bestseller-Autor im Wiley-VCH Verlag und Lehrbeauftragter der ASW-Akademie. Einschätzungen zu Cybersecurity und digitaler Souveränität erschienen u.a. in Welt am Sonntag, WDR, Deutschlandfunk und Handelsblatt.
10 Publikationen
- Einsatz von elektronischer Verschlüsselung - Hemmnisse für die Wirtschaft (2018)
- Kompass IT-Verschlüsselung - Orientierungshilfen für KMU (2018)
- IT Security Day 2025 - Live Hacking: KI in der Cybersicherheit (2025)
- Live Hacking - Credential Stuffing: Finanzrisiken jenseits Ransomware (2025)
- Keynote: Live Hacking Show - Ein Blick in die Welt der Cyberkriminalität (2025)
- Analyse von Angriffsflächen bei Shared-Hosting-Anbietern (2024)
- Gänsehaut garantiert: Die schaurigsten Funde aus dem Leben eines Pentesters (2022)
- IT Security Zertifizierungen — CISSP, T.I.S.P. & Co (Live-Webinar) (2023)
- Sicherheitsforum Online-Banking — Live Hacking (2021)
- Nipster im Netz und das Ende der Kreidezeit (2017)