Java Enterprise Security & Secure Integration

Große Sammlung und Praxispaket für Authentication, Authorization, sichere Integration, Upload/Download, Serialization, OpenShift Hardening, Audit, Observability und Security-Testing.

MarkdownPDFCode README
0 Treffer
Security BoundaryOAuth JWT FlowSecure UploadSecure Integration Resilience

Praxispaket Secure Enterprise Integration Lab

Das Paket enthält zusätzlich ein Maven-Multi-Modul-Beispielprojekt mit Security-Code, OpenShift-Manifests, CI/CD-Security-Gates und dokumentierten Entwurfsmustern.

code/secure-enterprise-integration-lab/
├─ pom.xml
├─ security-core/
├─ security-application/
├─ security-adapters/
├─ security-web/
├─ deploy/openshift/
├─ ci/github-actions/
└─ docs/design-patterns.md
Identity, Authentication und Token-Sicherheit10 Einträge

Authentifizierung klärt, wer eine Anfrage stellt. Diese Kategorie behandelt Token, Sessions, Service Accounts und maschinelle Identitäten.

s001: JWT nicht nur decodieren

Englischer technischer Begriff
JWT Signature Validation
Priorität
10/10
Warum wichtig
Ein JWT ist ohne Signaturprüfung nur base64-kodierter Text. In Enterprise-APIs entscheidet diese Prüfung über Identität, Mandant und Berechtigungen.
Typischer Fehler
Der Token wird mit Base64 gelesen und die Claims werden direkt vertraut.
Enterprise-Einordnung
Relevant für API-Gateways, Backend-Services, Partner-Integrationen und jede rollenbasierte Berechtigungsentscheidung.
Ausgangspunkt-Code
import java.util.Base64;

public final class UnsafeJwtReader {
    public String subject(String jwt) {
        String payload = jwt.split("\.")[1];
        return new String(Base64.getUrlDecoder().decode(payload)); // keine Signaturprüfung
    }
}
Ziel-Code
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Base64;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

public final class HmacJwtSignatureValidator {
    public boolean hasValidSignature(String jwt, byte[] secret) throws Exception {
        String[] parts = jwt.split("\.");
        if (parts.length != 3) return false;
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(new SecretKeySpec(secret, "HmacSHA256"));
        byte[] expected = mac.doFinal((parts[0] + "." + parts[1]).getBytes(StandardCharsets.US_ASCII));
        byte[] actual = Base64.getUrlDecoder().decode(parts[2]);
        return MessageDigest.isEqual(expected, actual);
    }
}

s002: Issuer und Audience erzwingen

Englischer technischer Begriff
Issuer and Audience Validation
Priorität
10/10
Warum wichtig
Ein korrekt signiertes Token kann trotzdem aus dem falschen System oder für einen anderen Client stammen.
Typischer Fehler
Der Service prüft nur, ob irgendein JWT gültig aussieht.
Enterprise-Einordnung
Wichtig bei mehreren Keycloak/IdP-Realms, Mandanten, Partner-Clients und internen Service-Accounts.
Ausgangspunkt-Code
public final class WeakClaimPolicy {
    public boolean trusted(TokenClaims claims) {
        return claims.subject() != null; // issuer/audience werden ignoriert
    }
}
record TokenClaims(String subject, String issuer, String audience) {}
Ziel-Code
import java.util.Set;

public final class StrictClaimPolicy {
    private final String expectedIssuer = "https://idp.acme.example/realms/enterprise";
    private final Set<String> allowedAudiences = Set.of("order-api", "partner-gateway");

    public boolean trusted(TokenClaims claims) {
        return claims.subject() != null
            && expectedIssuer.equals(claims.issuer())
            && allowedAudiences.contains(claims.audience());
    }
}
record TokenClaims(String subject, String issuer, String audience) {}

s003: Token-Ablauf mit Clock-Skew prüfen

Englischer technischer Begriff
Token Expiration and Clock Skew
Priorität
9/10
Warum wichtig
Produktionssysteme laufen auf vielen Nodes. Kleine Zeitabweichungen dürfen nicht zu Massenfehlern führen, abgelaufene Tokens aber auch nicht akzeptiert werden.
Typischer Fehler
Der Ablaufzeitpunkt wird gar nicht oder mit der lokalen Zeit ohne Toleranz geprüft.
Enterprise-Einordnung
Relevant für OpenShift-Cluster, API-Gateways, SSO und transaktionale Integrationen.
Ausgangspunkt-Code
import java.time.Instant;

public final class WeakExpiryCheck {
    public boolean active(long expiresAtEpochSeconds) {
        return expiresAtEpochSeconds > Instant.now().getEpochSecond();
    }
}
Ziel-Code
import java.time.Duration;
import java.time.Instant;

public final class TokenLifetimePolicy {
    private static final Duration CLOCK_SKEW = Duration.ofSeconds(60);

    public boolean active(long issuedAt, long expiresAt, Instant now) {
        Instant earliest = Instant.ofEpochSecond(issuedAt).minus(CLOCK_SKEW);
        Instant latest = Instant.ofEpochSecond(expiresAt).plus(CLOCK_SKEW);
        return !now.isBefore(earliest) && now.isBefore(latest);
    }
}

s004: Refresh Token Rotation erzwingen

Englischer technischer Begriff
Refresh Token Rotation
Priorität
9/10
Warum wichtig
Refresh Tokens sind langlebiger als Access Tokens. Wiederverwendung alter Tokens ist ein starkes Kompromittierungs-Signal.
Typischer Fehler
Refresh Tokens werden mehrfach akzeptiert und nie serverseitig invalidiert.
Enterprise-Einordnung
Wichtig für Portale, Mobile Clients, B2B-Clients und Zero-Trust-Sessions.
Ausgangspunkt-Code
public final class WeakRefreshService {
    public String refresh(String refreshToken) {
        return TokenIssuer.newAccessToken(refreshToken); // alter Token bleibt gültig
    }
}
Ziel-Code
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public final class RotatingRefreshTokenService {
    private final Set<String> usedTokenIds = ConcurrentHashMap.newKeySet();

    public TokenPair refresh(RefreshToken token) {
        if (!usedTokenIds.add(token.id())) {
            throw new SecurityException("Refresh token reuse detected");
        }
        return TokenIssuer.rotate(token.subject(), token.clientId());
    }
}
record RefreshToken(String id, String subject, String clientId) {}
record TokenPair(String accessToken, String refreshToken) {}
final class TokenIssuer { static TokenPair rotate(String s, String c){ return new TokenPair("access-"+s, "refresh-"+c); } }

s005: Passwörter nicht selbst hashen

Englischer technischer Begriff
Password Hashing Policy
Priorität
10/10
Warum wichtig
Passwortspeicherung ist ein Hochrisiko-Thema. Hashing braucht Salt, Iterationen, Algorithmuspflege und Migrationsstrategie.
Typischer Fehler
SHA-256 ohne Salt oder hart kodierte Salts werden verwendet.
Enterprise-Einordnung
Relevant für Legacy-Portale, interne Admin-Tools und Migrationsprojekte ohne externes Identity-System.
Ausgangspunkt-Code
import java.security.MessageDigest;

public final class WeakPasswordStore {
    public byte[] hash(String password) throws Exception {
        return MessageDigest.getInstance("SHA-256").digest(password.getBytes());
    }
}
Ziel-Code
import java.security.SecureRandom;
import java.util.Base64;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;

public final class Pbkdf2PasswordHasher {
    private static final SecureRandom RANDOM = new SecureRandom();

    public String hash(char[] password) throws Exception {
        byte[] salt = new byte[16];
        RANDOM.nextBytes(salt);
        PBEKeySpec spec = new PBEKeySpec(password, salt, 210_000, 256);
        byte[] hash = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256").generateSecret(spec).getEncoded();
        return "pbkdf2$210000$" + Base64.getEncoder().encodeToString(salt) + "$" + Base64.getEncoder().encodeToString(hash);
    }
}

s006: Service-Account-Token begrenzen

Englischer technischer Begriff
Bounded Service Account Token
Priorität
8/10
Warum wichtig
Service Tokens sollten nur das können, was der jeweilige Service wirklich braucht.
Typischer Fehler
Ein globaler Admin-Token wird in mehreren Services wiederverwendet.
Enterprise-Einordnung
Relevant für OpenShift Service Accounts, Batchjobs, interne Adapter und Plattformautomatisierung.
Ausgangspunkt-Code
apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-api
spec:
  template:
    spec:
      serviceAccountName: default
      automountServiceAccountToken: true
Ziel-Code
apiVersion: v1
kind: ServiceAccount
metadata:
  name: order-api-reader
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-api
spec:
  template:
    spec:
      serviceAccountName: order-api-reader
      automountServiceAccountToken: false

s007: API-Key nur gehasht speichern

Englischer technischer Begriff
API Key Hash Storage
Priorität
8/10
Warum wichtig
API-Keys sind faktisch Passwörter für Maschinen. Ein Datenbankdump darf keine direkt nutzbaren Keys enthalten.
Typischer Fehler
API-Keys werden im Klartext gespeichert und im Log ausgegeben.
Enterprise-Einordnung
Wichtig für Partner-Schnittstellen, Webhooks, B2B-Integration und Übergangsarchitekturen vor OAuth2.
Ausgangspunkt-Code
public record ApiClient(String clientId, String apiKey) {}

public final class ApiKeyRepository {
    public void save(ApiClient client) {
        System.out.println("store apiKey=" + client.apiKey());
    }
}
Ziel-Code
import java.security.MessageDigest;
import java.util.HexFormat;

public record ApiClientSecret(String clientId, String apiKeyHash) {}

public final class ApiKeyHasher {
    public ApiClientSecret protect(String clientId, String presentedApiKey) throws Exception {
        byte[] digest = MessageDigest.getInstance("SHA-256").digest(presentedApiKey.getBytes());
        return new ApiClientSecret(clientId, HexFormat.of().formatHex(digest));
    }
}

s008: Session-Fixation verhindern

Englischer technischer Begriff
Session Fixation Protection
Priorität
8/10
Warum wichtig
Nach erfolgreichem Login muss eine neue Session-ID entstehen, sonst kann ein Angreifer eine bekannte Session vorpräparieren.
Typischer Fehler
Die Anwendung behält die anonyme Session nach dem Login bei.
Enterprise-Einordnung
Relevant für ältere Servlet/JSP-Portale und Partner-Portale, die modernisiert werden.
Ausgangspunkt-Code
public final class LoginServlet {
    void login(HttpRequest req, User user) {
        req.session().put("user", user.name()); // gleiche Session-ID bleibt bestehen
    }
}
Ziel-Code
public final class LoginHandler {
    void login(HttpRequest req, User user) {
        req.invalidateSession();
        Session session = req.createSession();
        session.put("principal", user.name());
        session.put("loginTime", java.time.Instant.now().toString());
    }
}
interface HttpRequest { Session session(); void invalidateSession(); Session createSession(); }
interface Session { void put(String key, String value); }
record User(String name) {}

s009: mTLS für interne Hochrisiko-APIs

Englischer technischer Begriff
Mutual TLS for Service Integration
Priorität
8/10
Warum wichtig
Bei kritischen internen Integrationen reicht Netzwerkvertrauen allein nicht. mTLS bindet technische Identität an Zertifikate.
Typischer Fehler
Interne APIs werden nur per Service-Name geschützt und akzeptieren jeden Cluster-Client.
Enterprise-Einordnung
Relevant für Payment, Billing, Partner Clearing und privilegierte Backoffice-APIs.
Ausgangspunkt-Code
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all-internal
spec:
  podSelector: {}
  ingress:
    - {}
Ziel-Code
import java.net.http.HttpClient;
import javax.net.ssl.SSLContext;

public final class MtlsClientFactory {
    public HttpClient create(SSLContext serviceSslContext) {
        return HttpClient.newBuilder()
            .sslContext(serviceSslContext)
            .connectTimeout(java.time.Duration.ofSeconds(3))
            .build();
    }
}

s010: Anonyme Endpunkte explizit markieren

Englischer technischer Begriff
Explicit Anonymous Endpoints
Priorität
7/10
Warum wichtig
Offene Endpunkte müssen bewusst entschieden und getestet werden. Sonst entstehen versehentlich öffentliche Admin- oder Diagnose-URLs.
Typischer Fehler
Controller ohne Security-Metadaten gelten implizit als öffentlich.
Enterprise-Einordnung
Relevant für Health, OpenAPI, Login, öffentliche Downloads und Partner-Onboarding.
Ausgangspunkt-Code
public final class PartnerController {
    public Response getContract(String id) {
        return Response.ok("contract " + id); // Sicherheitsabsicht unklar
    }
}
Ziel-Code
@RequiresPermission("partner:contract:read")
public final class PartnerController {
    public Response getContract(Principal principal, String id) {
        return Response.ok("contract " + id + " for " + principal.subject());
    }
}
@interface RequiresPermission { String value(); }
record Principal(String subject) {}
record Response(String body) { static Response ok(String body){ return new Response(body); } }
Authorization, Rollen und Mandantengrenzen10 Einträge

Autorisierung entscheidet, was eine identifizierte Identität tun darf. Diese Kategorie schützt Objekte, Mandanten und kritische Aktionen.

s011: Deny-by-Default für Berechtigungen

Englischer technischer Begriff
Deny by Default Authorization
Priorität
10/10
Warum wichtig
Sichere Systeme erlauben nur explizit freigegebene Aktionen. Alles andere wird abgelehnt.
Typischer Fehler
Neue Endpunkte fallen versehentlich durch eine permissive Default-Regel.
Enterprise-Einordnung
Zentral für APIs, Admin-Funktionen, Mandantenfähigkeit und Governance.
Ausgangspunkt-Code
public final class PermissionGuard {
    public boolean allowed(User user, String permission) {
        return true; // während Entwicklung vergessen
    }
}
Ziel-Code
import java.util.Set;

public final class PermissionGuard {
    public void require(User user, String permission) {
        if (!user.permissions().contains(permission)) {
            throw new AccessDeniedException(permission);
        }
    }
}
record User(String subject, Set<String> permissions) {}
final class AccessDeniedException extends RuntimeException { AccessDeniedException(String p){ super("missing permission: " + p); } }

s012: Mandant aus Token statt Request lesen

Englischer technischer Begriff
Tenant from Token not Request
Priorität
10/10
Warum wichtig
Der Mandant ist eine Sicherheitsgrenze. Er darf nicht aus frei manipulierbaren Request-Parametern kommen.
Typischer Fehler
tenantId wird aus Query-Parametern übernommen.
Enterprise-Einordnung
Relevant für SaaS, Shared Databases, Partner-Portale und Backoffice-Sichten.
Ausgangspunkt-Code
public final class OrderQueryService {
    public List<Order> find(String tenantIdFromRequest) {
        return database.findByTenant(tenantIdFromRequest);
    }
    private final OrderDatabase database = new OrderDatabase();
}
record Order(String id) {}
class OrderDatabase { List<Order> findByTenant(String tenant){ return List.of(new Order("o-1")); } }
Ziel-Code
import java.util.List;

public final class OrderQueryService {
    private final OrderDatabase database = new OrderDatabase();

    public List<Order> find(SecurityPrincipal principal) {
        return database.findByTenant(principal.tenantId());
    }
}
record SecurityPrincipal(String subject, String tenantId) {}
record Order(String id) {}
class OrderDatabase { List<Order> findByTenant(String tenant){ return List.of(new Order("o-1")); } }

s013: BOLA/IDOR bei Ressourcen prüfen

Englischer technischer Begriff
Broken Object Level Authorization
Priorität
10/10
Warum wichtig
Objektzugriffe brauchen Besitz- oder Mandantenprüfung. Rollen allein reichen nicht.
Typischer Fehler
Jeder Benutzer mit Rolle USER kann jedes Objekt per ID lesen.
Enterprise-Einordnung
Kritisch für Order, Invoice, Contract, Document und Customer APIs.
Ausgangspunkt-Code
public final class InvoiceController {
    public Invoice get(String invoiceId, User user) {
        if (user.hasRole("USER")) return repo.find(invoiceId);
        throw new SecurityException();
    }
    private final InvoiceRepository repo = new InvoiceRepository();
}
Ziel-Code
public final class InvoiceController {
    private final InvoiceRepository repo = new InvoiceRepository();

    public Invoice get(String invoiceId, User user) {
        Invoice invoice = repo.find(invoiceId);
        if (!invoice.tenantId().equals(user.tenantId())) throw new SecurityException("tenant mismatch");
        return invoice;
    }
}
record User(String tenantId) { boolean hasRole(String role){ return true; } }
record Invoice(String id, String tenantId) {}
class InvoiceRepository { Invoice find(String id){ return new Invoice(id, "tenant-a"); } }

s014: Rollen in fachliche Permissions übersetzen

Englischer technischer Begriff
Role to Permission Mapping
Priorität
9/10
Warum wichtig
Rollen sind organisatorisch, Permissions sind fachlich-technisch prüfbar. Diese Trennung reduziert Wildwuchs.
Typischer Fehler
Im Code werden überall konkrete Rollennamen geprüft.
Enterprise-Einordnung
Relevant für Audits, Admin-Portale und fein granulare Enterprise-Berechtigungen.
Ausgangspunkt-Code
if (user.role().equals("SUPER_ADMIN") || user.role().equals("ORDER_MANAGER")) {
    order.cancel();
}
Ziel-Code
enum Permission { ORDER_CANCEL, ORDER_READ, INVOICE_READ }

public final class RolePermissionMapper {
    public java.util.Set<Permission> permissionsFor(String role) {
        return switch (role) {
            case "ORDER_MANAGER" -> java.util.Set.of(Permission.ORDER_CANCEL, Permission.ORDER_READ);
            case "AUDITOR" -> java.util.Set.of(Permission.ORDER_READ, Permission.INVOICE_READ);
            default -> java.util.Set.of();
        };
    }
}

s015: Method Security zentral erzwingen

Englischer technischer Begriff
Central Method Security
Priorität
9/10
Warum wichtig
Sicherheitsprüfungen müssen dort sitzen, wo fachliche Aktionen ausgelöst werden, nicht nur am Controller.
Typischer Fehler
Batch, REST und Messaging umgehen unterschiedliche Controller-Prüfungen.
Enterprise-Einordnung
Wichtig für Mehrkanal-Systeme: REST, Batch, JMS, Scheduler und Partner-Portale.
Ausgangspunkt-Code
public final class CancelOrderService {
    public void cancel(String orderId) {
        repository.cancel(orderId); // keine fachliche Berechtigungsprüfung
    }
}
Ziel-Code
public final class CancelOrderService {
    private final AuthorizationPolicy authorization;
    private final OrderRepository repository;

    public void cancel(SecurityPrincipal principal, String orderId) {
        authorization.require(principal, "order:cancel");
        repository.cancel(orderId);
    }
    public CancelOrderService(AuthorizationPolicy authorization, OrderRepository repository) {
        this.authorization = authorization; this.repository = repository;
    }
}
interface AuthorizationPolicy { void require(SecurityPrincipal p, String permission); }
interface OrderRepository { void cancel(String id); }
record SecurityPrincipal(String subject) {}

s016: Admin-Rechte fachlich schneiden

Englischer technischer Begriff
Least Privilege Admin Scope
Priorität
8/10
Warum wichtig
Admin ist selten eine einzige Berechtigung. Fachlich geschnittene Admin-Rechte reduzieren Schaden bei Fehlkonfiguration.
Typischer Fehler
Ein globales ADMIN darf Benutzer, Preise, Zahlungen und Logs ändern.
Enterprise-Einordnung
Relevant für große Backoffice-Landschaften mit mehreren Fachbereichen.
Ausgangspunkt-Code
boolean allowed = user.roles().contains("ADMIN");
Ziel-Code
import java.util.Set;

public final class AdminScopePolicy {
    public void requirePriceAdmin(Principal p) {
        if (!p.permissions().contains("price:write")) throw new SecurityException("price admin required");
    }
}
record Principal(String subject, Set<String> permissions) {}

s017: Permission Cache invalidieren

Englischer technischer Begriff
Permission Cache Invalidation
Priorität
7/10
Warum wichtig
Berechtigungsänderungen müssen zeitnah wirken. Sonst bleiben entfernte Rechte bis zum Cache-Ablauf aktiv.
Typischer Fehler
Permissions werden für Stunden gecacht und nie aktiv invalidiert.
Enterprise-Einordnung
Relevant für Admin-Portale, HR-getriebene Rollenwechsel und Incident-Reaktionen.
Ausgangspunkt-Code
public final class PermissionCache {
    private final Map<String, Set<String>> cache = new HashMap<>();
    public Set<String> permissions(String user) { return cache.computeIfAbsent(user, this::load); }
    private Set<String> load(String user) { return Set.of("order:write"); }
}
Ziel-Code
import java.time.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public final class ExpiringPermissionCache {
    private final Map<String, Entry> cache = new ConcurrentHashMap<>();
    public Set<String> permissions(String user) {
        Entry entry = cache.get(user);
        if (entry == null || entry.validUntil().isBefore(Instant.now())) {
            entry = new Entry(load(user), Instant.now().plus(Duration.ofMinutes(5)));
            cache.put(user, entry);
        }
        return entry.permissions();
    }
    public void invalidate(String user) { cache.remove(user); }
    private Set<String> load(String user) { return Set.of("order:read"); }
    record Entry(Set<String> permissions, Instant validUntil) {}
}

s018: UI-Prüfung nie als Security betrachten

Englischer technischer Begriff
UI Authorization is not Security
Priorität
9/10
Warum wichtig
Buttons verstecken ist Usability, keine Sicherheit. Der Server muss jede Aktion selbst prüfen.
Typischer Fehler
Ein gefährlicher Endpoint verlässt sich darauf, dass der Button nicht angezeigt wird.
Enterprise-Einordnung
Relevant für Angular/React/Thymeleaf/JSP-Portale und Backoffice-Funktionen.
Ausgangspunkt-Code
public final class PriceController {
    public void updatePrice(String sku, BigDecimal price) {
        priceService.update(sku, price); // UI hat Button versteckt, API prüft nicht
    }
}
Ziel-Code
import java.math.BigDecimal;

public final class PriceController {
    private final AuthorizationPolicy auth;
    private final PriceService priceService;
    public void updatePrice(Principal principal, String sku, BigDecimal price) {
        auth.require(principal, "price:write");
        priceService.update(sku, price);
    }
    public PriceController(AuthorizationPolicy auth, PriceService priceService) { this.auth = auth; this.priceService = priceService; }
}
interface AuthorizationPolicy { void require(Principal p, String permission); }
interface PriceService { void update(String sku, BigDecimal price); }
record Principal(String subject) {}

s019: Zugriffsverweigerung auditieren

Englischer technischer Begriff
Audit Access Denied
Priorität
8/10
Warum wichtig
Abgelehnte Zugriffe zeigen Fehlkonfigurationen, Angriffe oder Rollenprobleme. Ohne Audit fehlt die Spur.
Typischer Fehler
AccessDenied wird nur als HTTP 403 beantwortet und nirgends protokolliert.
Enterprise-Einordnung
Wichtig für Compliance, SOC, Incident-Analyse und Partner-Streitfälle.
Ausgangspunkt-Code
catch (AccessDeniedException ex) {
    return Response.status(403);
}
Ziel-Code
public final class AccessDeniedHandler {
    private final AuditSink audit;
    public Response handle(Principal p, String action, RuntimeException ex) {
        audit.record(new AuditEvent("ACCESS_DENIED", p.subject(), action, java.time.Instant.now()));
        return Response.status(403, "access denied");
    }
}
interface AuditSink { void record(AuditEvent event); }
record AuditEvent(String type, String subject, String action, java.time.Instant at) {}
record Principal(String subject) {}
record Response(int status, String body) { static Response status(int s, String b){ return new Response(s,b); } }

s020: Berechtigungsregeln testbar halten

Englischer technischer Begriff
Testable Authorization Policy
Priorität
8/10
Warum wichtig
Policies müssen in Unit-Tests ohne Webcontainer prüfbar sein. Sonst verlagert sich Security in schwer testbare Infrastruktur.
Typischer Fehler
Regeln sind über mehrere Controller, Filter und UI-Flags verteilt.
Enterprise-Einordnung
Relevant für große Teams und langlebige Berechtigungsmodelle.
Ausgangspunkt-Code
public final class OrderController {
    boolean allowed(User u) { return u.role().equals("ADMIN") || u.name().equals("batch"); }
}
Ziel-Code
public final class OrderPolicy {
    public boolean canCancel(User user, Order order) {
        return user.permissions().contains("order:cancel") && user.tenantId().equals(order.tenantId());
    }
}
record User(String tenantId, java.util.Set<String> permissions) {}
record Order(String id, String tenantId) {}
Sichere HTTP-Integration und Resilience10 Einträge

Schnittstellen müssen sicher, begrenzt, nachvollziehbar und fehlertolerant sein. Diese Kategorie verbindet Security mit Integration und Betrieb.

s021: Timeouts für jeden HTTP-Client setzen

Englischer technischer Begriff
HTTP Client Timeouts
Priorität
10/10
Warum wichtig
Ohne Timeout kann ein Partner-System Threads, Virtual Threads oder Connection Pools blockieren.
Typischer Fehler
HttpClient wird ohne connect- und request-timeout gebaut.
Enterprise-Einordnung
Relevant für Payment, ERP, Partner-APIs, Portal-Backend und Batch-Integration.
Ausgangspunkt-Code
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create(url)).GET().build();
client.send(request, BodyHandlers.ofString());
Ziel-Code
import java.net.URI;
import java.net.http.*;
import java.time.Duration;

public final class PartnerClient {
    private final HttpClient client = HttpClient.newBuilder()
        .connectTimeout(Duration.ofSeconds(2))
        .build();

    public String getStatus(URI uri) throws Exception {
        HttpRequest request = HttpRequest.newBuilder(uri)
            .timeout(Duration.ofSeconds(4))
            .GET().build();
        return client.send(request, HttpResponse.BodyHandlers.ofString()).body();
    }
}

s022: Retries nur für idempotente Operationen

Englischer technischer Begriff
Idempotent Retry Policy
Priorität
9/10
Warum wichtig
Retries können doppelte Zahlungen oder doppelte Bestellungen auslösen. Nur idempotente Aktionen dürfen automatisch wiederholt werden.
Typischer Fehler
POST wird bei jedem Timeout blind erneut gesendet.
Enterprise-Einordnung
Kritisch für Payment, Order Creation, Invoice Export und externe Buchungssysteme.
Ausgangspunkt-Code
for (int i = 0; i < 3; i++) {
    client.send(createPaymentRequest(), BodyHandlers.ofString());
}
Ziel-Code
public final class RetryPolicy {
    public boolean mayRetry(String method, int statusCode) {
        boolean idempotent = method.equals("GET") || method.equals("PUT") || method.equals("DELETE");
        boolean transientFailure = statusCode == 429 || statusCode == 503 || statusCode == 504;
        return idempotent && transientFailure;
    }
}

s023: Idempotency-Key bei Zahlungs- oder Order-APIs

Englischer technischer Begriff
Idempotency Key
Priorität
10/10
Warum wichtig
Ein Idempotency-Key macht eine fachliche Aktion wiederholbar, ohne sie mehrfach auszuführen.
Typischer Fehler
Der Client sendet dieselbe Zahlung mehrfach ohne fachliche Deduplizierung.
Enterprise-Einordnung
Relevant für B2B, Payment, Order Intake, Batch-Replays und Fehlerwiederholung.
Ausgangspunkt-Code
HttpRequest request = HttpRequest.newBuilder(paymentUri)
    .POST(BodyPublishers.ofString(json))
    .build();
Ziel-Code
import java.net.http.HttpRequest;

HttpRequest request = HttpRequest.newBuilder(paymentUri)
    .header("Idempotency-Key", orderId + "-" + paymentAttempt)
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(json))
    .build();

s024: SSRF durch Outbound-Allowlist verhindern

Englischer technischer Begriff
Outbound Allowlist for SSRF Protection
Priorität
10/10
Warum wichtig
Wenn URLs aus Benutzereingaben in HTTP-Clients landen, kann interne Infrastruktur angegriffen werden.
Typischer Fehler
Die Anwendung ruft beliebige URLs aus einem Request-Parameter auf.
Enterprise-Einordnung
Wichtig für Webhooks, Dokument-Importer, Partner-Callbacks und Datei-Download-Funktionen.
Ausgangspunkt-Code
public byte[] fetch(String urlFromRequest) throws Exception {
    return http.get(URI.create(urlFromRequest));
}
Ziel-Code
import java.net.URI;
import java.util.Set;

public final class OutboundUrlPolicy {
    private final Set<String> allowedHosts = Set.of("api.partner-a.example", "files.partner-b.example");

    public URI requireAllowed(String candidate) {
        URI uri = URI.create(candidate);
        if (!"https".equals(uri.getScheme()) || !allowedHosts.contains(uri.getHost())) {
            throw new SecurityException("outbound host not allowed: " + uri.getHost());
        }
        return uri;
    }
}

s025: Korrelation-ID sicher weiterreichen

Englischer technischer Begriff
Correlation ID Propagation
Priorität
7/10
Warum wichtig
Korrelation-IDs verbinden Logs, Traces und Audits, dürfen aber keine personenbezogenen oder geheimen Daten enthalten.
Typischer Fehler
E-Mail-Adresse oder Token wird als Correlation-ID verwendet.
Enterprise-Einordnung
Relevant für Microservices, OpenTelemetry, Incident-Analyse und Partner-Support.
Ausgangspunkt-Code
request.header("X-Correlation-ID", user.email());
Ziel-Code
import java.util.UUID;

public final class CorrelationId {
    public static String fromHeaderOrNew(String headerValue) {
        if (headerValue != null && headerValue.matches("[a-zA-Z0-9_.:-]{8,80}")) return headerValue;
        return UUID.randomUUID().toString();
    }
}

s026: Fehlerantworten ohne interne Details

Englischer technischer Begriff
Safe Error Response
Priorität
9/10
Warum wichtig
Fehlerantworten müssen hilfreich, aber nicht verräterisch sein. Stacktraces und SQL-Details gehören nicht an Clients.
Typischer Fehler
Exception-Text wird direkt als HTTP-Response ausgegeben.
Enterprise-Einordnung
Wichtig für öffentliche APIs, Partner-Schnittstellen und Security-Audits.
Ausgangspunkt-Code
catch (Exception ex) {
    return Response.status(500, ex.toString());
}
Ziel-Code
public final class ErrorMapper {
    public ApiError toClientError(Exception ex, String correlationId) {
        logInternal(correlationId, ex);
        return new ApiError("INTERNAL_ERROR", "Die Anfrage konnte nicht verarbeitet werden.", correlationId);
    }
    private void logInternal(String correlationId, Exception ex) { System.err.println(correlationId + " " + ex.getClass().getName()); }
}
record ApiError(String code, String message, String correlationId) {}

s027: Circuit Breaker für instabile Partner

Englischer technischer Begriff
Circuit Breaker
Priorität
8/10
Warum wichtig
Ein Circuit Breaker verhindert, dass ein instabiler Partner das eigene System blockiert.
Typischer Fehler
Jeder Request läuft weiter in denselben Timeout, obwohl der Partner bereits down ist.
Enterprise-Einordnung
Relevant für synchrone Partner-APIs, Payment Provider und Legacy-Systeme.
Ausgangspunkt-Code
public String callPartner() throws Exception {
    return partnerClient.call();
}
Ziel-Code
import java.time.*;
import java.util.concurrent.atomic.AtomicInteger;

public final class SimpleCircuitBreaker {
    private final AtomicInteger failures = new AtomicInteger();
    private volatile Instant openUntil = Instant.EPOCH;

    public boolean allowRequest() {
        return Instant.now().isAfter(openUntil);
    }
    public void recordFailure() {
        if (failures.incrementAndGet() >= 5) openUntil = Instant.now().plusSeconds(30);
    }
    public void recordSuccess() { failures.set(0); openUntil = Instant.EPOCH; }
}

s028: Rate Limiting pro Client

Englischer technischer Begriff
Client Rate Limiting
Priorität
8/10
Warum wichtig
Rate Limits schützen Systeme gegen Missbrauch, Fehlkonfiguration und unfaire Ressourcennutzung.
Typischer Fehler
Alle Clients teilen sich ein unkontrolliertes globales Limit oder gar kein Limit.
Enterprise-Einordnung
Relevant für öffentliche APIs, Partner-Portale und API-Gateways.
Ausgangspunkt-Code
public boolean allowed(String clientId) {
    return true;
}
Ziel-Code
import java.time.Instant;
import java.util.concurrent.ConcurrentHashMap;

public final class FixedWindowRateLimiter {
    private final ConcurrentHashMap<String, Counter> counters = new ConcurrentHashMap<>();
    public boolean allowed(String clientId) {
        long minute = Instant.now().getEpochSecond() / 60;
        Counter c = counters.compute(clientId, (k, old) -> old == null || old.minute != minute ? new Counter(minute, 1) : old.increment());
        return c.count <= 600;
    }
    record Counter(long minute, int count) { Counter increment(){ return new Counter(minute, count + 1); } }
}

s029: HMAC-Signatur für Webhooks

Englischer technischer Begriff
Webhook HMAC Signature
Priorität
9/10
Warum wichtig
Webhooks müssen beweisen, dass sie vom erwarteten Sender stammen und unterwegs nicht verändert wurden.
Typischer Fehler
Webhook-Payload wird ohne Signatur angenommen.
Enterprise-Einordnung
Relevant für Payment-Callbacks, Logistik-Events und Partner-Benachrichtigungen.
Ausgangspunkt-Code
public void receive(String payload) {
    eventService.apply(payload); // jeder kann Events senden
}
Ziel-Code
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;

public final class WebhookSignatureVerifier {
    public boolean valid(byte[] payload, byte[] secret, byte[] signature) throws Exception {
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(new SecretKeySpec(secret, "HmacSHA256"));
        return MessageDigest.isEqual(mac.doFinal(payload), signature);
    }
}

s030: Backpressure bei Partner-Import

Englischer technischer Begriff
Integration Backpressure
Priorität
8/10
Warum wichtig
Wenn externe Systeme schneller liefern als verarbeitet werden kann, braucht die Anwendung Druckbegrenzung.
Typischer Fehler
Import liest unbegrenzt Events in den Speicher.
Enterprise-Einordnung
Relevant für CSV/JSON-Importe, Messaging-Bridges, Partner-Feeds und Batchjobs.
Ausgangspunkt-Code
List<Event> all = partnerClient.readAll();
all.forEach(processor::process);
Ziel-Code
import java.util.concurrent.*;

public final class BoundedPartnerImport {
    private final BlockingQueue<Event> queue = new ArrayBlockingQueue<>(1_000);
    public boolean offer(Event event) throws InterruptedException {
        return queue.offer(event, 200, TimeUnit.MILLISECONDS);
    }
    public Event take() throws InterruptedException { return queue.take(); }
}
record Event(String id, String body) {}
Dateioperationen, Upload und Download10 Einträge

Dateien sind in Enterprise-Systemen oft die gefährlichste Integrationsfläche: Pfade, Formate, Archive, Exporte und Objektberechtigungen müssen sauber begrenzt werden.

s031: Path Traversal bei Downloads blockieren

Englischer technischer Begriff
Path Traversal Protection
Priorität
10/10
Warum wichtig
Dateipfade aus Requests dürfen niemals direkt ins Dateisystem gehen. Sonst werden Konfigurationsdateien, Secrets oder andere Mandanten erreichbar.
Typischer Fehler
Dateiname wird direkt an Path.resolve übergeben und normalisiert nicht geprüft.
Enterprise-Einordnung
Relevant für Download-Portale, Dokumentenarchive, Rechnungen, Partner-Dateien und Batch-Exports.
Ausgangspunkt-Code
Path base = Path.of("/srv/app/files");
Path target = base.resolve(requestedFileName);
return Files.readAllBytes(target);
Ziel-Code
import java.nio.file.*;

public final class SafeDownloadPath {
    private final Path base = Path.of("/srv/app/files").toAbsolutePath().normalize();
    public Path resolve(String requestedFileName) {
        Path target = base.resolve(requestedFileName).normalize();
        if (!target.startsWith(base)) throw new SecurityException("path traversal blocked");
        return target;
    }
}

s032: Upload-Größe hart begrenzen

Englischer technischer Begriff
Upload Size Limit
Priorität
9/10
Warum wichtig
Große Uploads können Speicher, Disk oder Virenscanner blockieren. Limits müssen schon beim Streamen greifen.
Typischer Fehler
Datei wird vollständig in byte[] gelesen und erst danach geprüft.
Enterprise-Einordnung
Relevant für Partner-Portale, Beleg-Upload, CSV-Import und Dokumentenablage.
Ausgangspunkt-Code
byte[] bytes = inputStream.readAllBytes();
repository.save(bytes);
Ziel-Code
import java.io.*;

public final class LimitedUploadReader {
    public byte[] read(InputStream in, long maxBytes) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] buffer = new byte[8192];
        long total = 0;
        for (int read; (read = in.read(buffer)) != -1;) {
            total += read;
            if (total > maxBytes) throw new IOException("upload too large");
            out.write(buffer, 0, read);
        }
        return out.toByteArray();
    }
}

s033: Dateiendung und Inhalt prüfen

Englischer technischer Begriff
File Extension and Content Validation
Priorität
8/10
Warum wichtig
Dateiendungen sind Benutzereingaben. Der Inhalt muss zu erlaubten Formaten passen.
Typischer Fehler
Ein .csv wird akzeptiert, obwohl es eine ausführbare Datei ist.
Enterprise-Einordnung
Wichtig für Upload, Import, Archivierung und Malware-Prävention.
Ausgangspunkt-Code
if (fileName.endsWith(".csv")) {
    importCsv(input);
}
Ziel-Code
import java.io.*;
import java.nio.charset.StandardCharsets;

public final class CsvUploadPolicy {
    public void requireCsv(String fileName, byte[] firstBytes) {
        if (!fileName.toLowerCase().endsWith(".csv")) throw new SecurityException("extension not allowed");
        String prefix = new String(firstBytes, 0, Math.min(firstBytes.length, 128), StandardCharsets.UTF_8);
        if (prefix.indexOf('') >= 0 || prefix.startsWith("MZ")) throw new SecurityException("content not csv-like");
    }
}

s034: Zip Slip beim Entpacken verhindern

Englischer technischer Begriff
Zip Slip Protection
Priorität
10/10
Warum wichtig
Archiv-Einträge können relative Pfade enthalten. Ohne Prüfung schreibt ein ZIP außerhalb des Zielordners.
Typischer Fehler
ZipEntry-Name wird direkt in eine Datei geschrieben.
Enterprise-Einordnung
Relevant für Datenimporte, Herstellerpakete, Support-Uploads und Massendokumente.
Ausgangspunkt-Code
Path out = targetDir.resolve(zipEntry.getName());
Files.copy(zip.getInputStream(zipEntry), out);
Ziel-Code
import java.nio.file.*;
import java.util.zip.ZipEntry;

public final class SafeZipExtractor {
    public Path resolveEntry(Path targetDir, ZipEntry entry) {
        Path root = targetDir.toAbsolutePath().normalize();
        Path out = root.resolve(entry.getName()).normalize();
        if (!out.startsWith(root)) throw new SecurityException("zip slip blocked: " + entry.getName());
        return out;
    }
}

s035: CSV-Formel-Injection verhindern

Englischer technischer Begriff
CSV Formula Injection Protection
Priorität
8/10
Warum wichtig
Excel interpretiert Zellen mit =, +, - oder @ als Formeln. Exporte können so gefährliche Inhalte transportieren.
Typischer Fehler
Benutzereingaben werden direkt in CSV geschrieben.
Enterprise-Einordnung
Relevant für Backoffice-Exports, Reporting und Kundenlisten.
Ausgangspunkt-Code
writer.write(customerName + ";" + amount + "
");
Ziel-Code
public final class SafeCsvCell {
    public String escape(String value) {
        String v = value == null ? "" : value.replace(""", """");
        if (!v.isEmpty() && "=+-@".indexOf(v.charAt(0)) >= 0) v = "'" + v;
        return """ + v + """;
    }
}

s036: Content-Disposition sicher setzen

Englischer technischer Begriff
Safe Content-Disposition
Priorität
7/10
Warum wichtig
Download-Dateinamen dürfen keine Header manipulieren und sollten Browser-sicher kodiert sein.
Typischer Fehler
Dateiname wird direkt in Header geschrieben.
Enterprise-Einordnung
Relevant für Rechnungsdownloads, Export-Dateien und Dokumentenportale.
Ausgangspunkt-Code
response.header("Content-Disposition", "attachment; filename=" + fileName);
Ziel-Code
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

public final class DownloadHeaderFactory {
    public String attachment(String fileName) {
        String safe = fileName.replaceAll("[\r\n\\/]", "_");
        String encoded = URLEncoder.encode(safe, StandardCharsets.UTF_8).replace("+", "%20");
        return "attachment; filename="download"; filename*=UTF-8''" + encoded;
    }
}

s037: Temporäre Dateien sicher erzeugen

Englischer technischer Begriff
Secure Temporary Files
Priorität
7/10
Warum wichtig
Temporäre Dateien können Race Conditions oder Rechteprobleme verursachen. Sie müssen zufällig, begrenzt und löschbar sein.
Typischer Fehler
Ein fester Dateiname in /tmp wird verwendet.
Enterprise-Einordnung
Wichtig für Upload-Verarbeitung, PDF-Erzeugung und Batch-Exports.
Ausgangspunkt-Code
Path tmp = Path.of("/tmp/upload.csv");
Files.writeString(tmp, content);
Ziel-Code
import java.nio.file.*;

public final class TempFileService {
    public Path createUploadTemp(byte[] content) throws java.io.IOException {
        Path tmp = Files.createTempFile("upload-", ".bin");
        Files.write(tmp, content, StandardOpenOption.TRUNCATE_EXISTING);
        tmp.toFile().deleteOnExit();
        return tmp;
    }
}

s038: Upload vor Verarbeitung scannen

Englischer technischer Begriff
Upload Scan Hook
Priorität
8/10
Warum wichtig
Der Upload-Pfad sollte einen expliziten Security-Gate haben, damit Malware-Scan, DLP oder Quarantäne integriert werden kann.
Typischer Fehler
Datei wird sofort fachlich importiert.
Enterprise-Einordnung
Relevant für regulierte Umgebungen und B2B-Dateiaustausch.
Ausgangspunkt-Code
documentStore.save(uploadedFile);
importer.importNow(uploadedFile);
Ziel-Code
public final class UploadPipeline {
    private final MalwareScanner scanner;
    private final DocumentStore store;
    public StoredDocument accept(UploadedFile file) {
        scanner.requireClean(file.bytes());
        return store.save(file);
    }
}
interface MalwareScanner { void requireClean(byte[] bytes); }
interface DocumentStore { StoredDocument save(UploadedFile file); }
record UploadedFile(String name, byte[] bytes) {}
record StoredDocument(String id) {}

s039: Download mit Objektberechtigung koppeln

Englischer technischer Begriff
Authorized File Download
Priorität
9/10
Warum wichtig
Datei-Download ist ein Objektzugriff. Rechte müssen am Dokument, Mandant und Zweck geprüft werden.
Typischer Fehler
Jeder eingeloggte Benutzer kann per fileId laden.
Enterprise-Einordnung
Relevant für Vertragsdokumente, Rechnungen, Exporte und Support-Anhänge.
Ausgangspunkt-Code
public byte[] download(String fileId) {
    return fileStore.read(fileId);
}
Ziel-Code
public final class DocumentDownloadService {
    private final AuthorizationPolicy auth;
    private final DocumentRepository repo;
    public byte[] download(Principal principal, String documentId) {
        Document doc = repo.find(documentId);
        auth.requireTenant(principal, doc.tenantId());
        return doc.bytes();
    }
}
interface AuthorizationPolicy { void requireTenant(Principal p, String tenantId); }
interface DocumentRepository { Document find(String id); }
record Principal(String tenantId) {}
record Document(String tenantId, byte[] bytes) {}

s040: Hash für Datei-Integrität berechnen

Englischer technischer Begriff
File Integrity Hash
Priorität
7/10
Warum wichtig
Hashes machen nachvollziehbar, ob eine Datei unverändert gespeichert und verarbeitet wurde.
Typischer Fehler
Importe werden ohne Prüfsumme abgelegt.
Enterprise-Einordnung
Wichtig für Audit, Reklamationen, Reprocessing und Partner-Dateiaustausch.
Ausgangspunkt-Code
store.save(bytes);
log.info("file imported");
Ziel-Code
import java.security.MessageDigest;
import java.util.HexFormat;

public final class FileFingerprint {
    public String sha256(byte[] bytes) throws Exception {
        return HexFormat.of().formatHex(MessageDigest.getInstance("SHA-256").digest(bytes));
    }
}
Serialization, XML, JSON, CSV und Datenabfluss10 Einträge

Serialisierung ist eine Integrationsgrenze. Diese Kategorie schützt Parser, Mapping, Logging, Encoding und Nachrichtenversionen.

s041: XML External Entity deaktivieren

Englischer technischer Begriff
XXE Protection
Priorität
10/10
Warum wichtig
XML-Parser können externe Entitäten laden und dadurch Dateien oder interne URLs lesen.
Typischer Fehler
DocumentBuilderFactory wird mit Default-Konfiguration verwendet.
Enterprise-Einordnung
Relevant für SOAP, XML-Importe, Partner-Nachrichten und Legacy-Systeme.
Ausgangspunkt-Code
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
Document doc = factory.newDocumentBuilder().parse(inputStream);
Ziel-Code
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilderFactory;

public final class SecureXmlFactory {
    public DocumentBuilderFactory create() throws Exception {
        DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
        f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
        f.setFeature("http://xml.org/sax/features/external-general-entities", false);
        f.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
        f.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
        f.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
        f.setXIncludeAware(false);
        f.setExpandEntityReferences(false);
        return f;
    }
}

s042: Java Native Serialization vermeiden

Englischer technischer Begriff
Avoid Java Native Serialization
Priorität
10/10
Warum wichtig
ObjectInputStream kann gefährliche Objektgraphen erzeugen. Für externe Daten ist Java-Serialization ungeeignet.
Typischer Fehler
Objekte werden direkt aus Request-Bytes deserialisiert.
Enterprise-Einordnung
Relevant für alte RMI/EJB-Altlasten, Caches, Sessions und Messaging.
Ausgangspunkt-Code
ObjectInputStream in = new ObjectInputStream(requestBody);
Command command = (Command) in.readObject();
command.execute();
Ziel-Code
public record CreateOrderCommand(String customerId, java.util.List<String> skuIds) {}

public final class CommandValidator {
    public void requireValid(CreateOrderCommand command) {
        if (command.customerId() == null || command.customerId().isBlank()) throw new IllegalArgumentException("customer required");
        if (command.skuIds().size() > 100) throw new IllegalArgumentException("too many lines");
    }
}

s043: JSON nur in DTOs binden

Englischer technischer Begriff
JSON DTO Binding Boundary
Priorität
8/10
Warum wichtig
Externes JSON sollte in explizite DTOs laufen, nicht direkt in Domain- oder Entity-Objekte.
Typischer Fehler
Request JSON bindet direkt auf JPA Entity inklusive interner Felder.
Enterprise-Einordnung
Relevant für REST APIs, Partner-Schnittstellen und Mass Assignment Schutz.
Ausgangspunkt-Code
public Response update(CustomerEntity entityFromRequest) {
    customerRepository.save(entityFromRequest);
    return Response.ok();
}
Ziel-Code
public record UpdateCustomerRequest(String displayName, String phoneNumber) {}

public final class CustomerUpdater {
    public void update(Customer customer, UpdateCustomerRequest request) {
        customer.changeDisplayName(request.displayName());
        customer.changePhoneNumber(request.phoneNumber());
    }
}

s044: Polymorphe JSON-Typen begrenzen

Englischer technischer Begriff
Polymorphic JSON Type Restriction
Priorität
9/10
Warum wichtig
Freie Typinformationen in JSON können gefährliche Klassen oder unerwartete Objektarten erzeugen.
Typischer Fehler
Default Typing wird global aktiviert.
Enterprise-Einordnung
Relevant für JSON APIs, Message Bus Payloads und Integration mit Legacy-Adaptern.
Ausgangspunkt-Code
mapper.activateDefaultTyping(typeValidator, ObjectMapper.DefaultTyping.EVERYTHING);
Ziel-Code
sealed interface PartnerEvent permits OrderReceived, DeliveryFailed {}
record OrderReceived(String orderId) implements PartnerEvent {}
record DeliveryFailed(String orderId, String reason) implements PartnerEvent {}

public final class PartnerEventFactory {
    public PartnerEvent fromType(String type, String orderId, String reason) {
        return switch (type) {
            case "ORDER_RECEIVED" -> new OrderReceived(orderId);
            case "DELIVERY_FAILED" -> new DeliveryFailed(orderId, reason);
            default -> throw new IllegalArgumentException("unknown event type");
        };
    }
}

s045: Output Encoding pro Zielkontext

Englischer technischer Begriff
Context Specific Output Encoding
Priorität
9/10
Warum wichtig
HTML, JSON, CSV und Logs brauchen unterschiedliche Escape-Regeln. Ein allgemeines replace reicht nicht.
Typischer Fehler
Benutzerdaten werden ungefiltert in HTML eingebettet.
Enterprise-Einordnung
Relevant für Portale, E-Mail-Templates, Admin-UIs und Reports.
Ausgangspunkt-Code
String html = "<div>" + customerName + "</div>";
Ziel-Code
public final class HtmlEscaper {
    public String text(String value) {
        return value.replace("&", "&amp;")
            .replace("<", "&lt;")
            .replace(">", "&gt;")
            .replace(""", "&quot;")
            .replace("'", "&#x27;");
    }
}

s046: PII vor Logging maskieren

Englischer technischer Begriff
PII Log Masking
Priorität
9/10
Warum wichtig
Logs landen in vielen Systemen. Personenbezogene und geheime Daten müssen vor dem Schreiben maskiert werden.
Typischer Fehler
Tokens, IBANs oder E-Mails werden direkt geloggt.
Enterprise-Einordnung
Relevant für Observability, Support, SIEM und Datenschutz.
Ausgangspunkt-Code
log.info("payment request=" + requestJson);
Ziel-Code
public final class LogMasker {
    public String mask(String message) {
        return message
            .replaceAll("Bearer [A-Za-z0-9._-]+", "Bearer ***")
            .replaceAll("[A-Z]{2}[0-9A-Z]{13,32}", "IBAN-***")
            .replaceAll("[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+", "email-***");
    }
}

s047: Schema-Version in Nachrichten tragen

Englischer technischer Begriff
Message Schema Version
Priorität
7/10
Warum wichtig
Versionierte Nachrichten erlauben kompatible Weiterentwicklung ohne Big Bang Deployment.
Typischer Fehler
Producer ändert JSON-Struktur ohne Versionsfeld.
Enterprise-Einordnung
Wichtig für Messaging, Outbox, Partner-Events und Batch-Importe.
Ausgangspunkt-Code
{
  "orderId": "O-4711",
  "status": "PAID"
}
Ziel-Code
{
  "schemaVersion": 2,
  "eventType": "OrderPaid",
  "eventId": "evt-20260707-001",
  "orderId": "O-4711",
  "paidAt": "2026-07-07T12:00:00Z"
}

s048: Validierung vor Mapping durchführen

Englischer technischer Begriff
Validate Before Mapping
Priorität
8/10
Warum wichtig
Ungültige externe Daten sollen nicht in Domain-Objekte oder Datenbankzustände gelangen.
Typischer Fehler
Mapper normalisiert ungültige Werte stillschweigend.
Enterprise-Einordnung
Relevant für APIs, CSV-Importe, Partner-Nachrichten und Batchjobs.
Ausgangspunkt-Code
Order order = mapper.toOrder(request);
repository.save(order);
Ziel-Code
public final class OrderRequestValidator {
    public void validate(CreateOrderRequest request) {
        if (request.customerId() == null || request.customerId().isBlank()) throw new IllegalArgumentException("customerId required");
        if (request.lines().isEmpty()) throw new IllegalArgumentException("at least one line required");
    }
}
record CreateOrderRequest(String customerId, java.util.List<String> lines) {}

s049: Zeichensatz explizit setzen

Englischer technischer Begriff
Explicit Charset
Priorität
7/10
Warum wichtig
Default Charset kann je Runtime variieren. Security- und Datenfehler entstehen oft durch stille Encoding-Wechsel.
Typischer Fehler
String/Bytes Konvertierung nutzt Plattform-Default.
Enterprise-Einordnung
Relevant für CSV, Signaturen, Hashing, HTTP und Legacy-Dateien.
Ausgangspunkt-Code
byte[] bytes = payload.getBytes();
String text = new String(bytes);
Ziel-Code
import java.nio.charset.StandardCharsets;

byte[] bytes = payload.getBytes(StandardCharsets.UTF_8);
String text = new String(bytes, StandardCharsets.UTF_8);

s050: Signatur über kanonische Payload bilden

Englischer technischer Begriff
Canonical Payload Signing
Priorität
8/10
Warum wichtig
Bei signierten Nachrichten muss klar sein, welche Bytes signiert wurden. Formatierungsänderungen dürfen Signaturen nicht zufällig brechen.
Typischer Fehler
Die Signatur wird über hübsch formatiertes JSON gebildet.
Enterprise-Einordnung
Relevant für Webhooks, Partner-Events und revisionssichere Schnittstellen.
Ausgangspunkt-Code
byte[] signature = signer.sign(prettyPrintedJson.getBytes());
Ziel-Code
import java.nio.charset.StandardCharsets;

public final class CanonicalSignerInput {
    public byte[] bytes(String method, String path, String sha256Body) {
        String canonical = method.toUpperCase() + "
" + path + "
" + sha256Body;
        return canonical.getBytes(StandardCharsets.UTF_8);
    }
}
Secrets, OpenShift und Runtime-Hardening10 Einträge

Diese Kategorie behandelt sichere Deployment-Konfiguration: Secrets, Container-Rechte, Netzwerkgrenzen, TLS und Ressourcenlimits.

s051: Secrets nicht in Git oder POM

Englischer technischer Begriff
No Secrets in Source Control
Priorität
10/10
Warum wichtig
Secrets in Code-Repositories verbreiten sich in Build-Logs, Artefakten, Backups und Entwicklerrechnern.
Typischer Fehler
Passwort steht direkt in application.properties oder pom.xml.
Enterprise-Einordnung
Relevant für Maven, CI/CD, OpenShift, Datenbanken und externe Partner.
Ausgangspunkt-Code
payment.api.key=live_1234567890
spring.datasource.password=secret-password
Ziel-Code
apiVersion: v1
kind: Secret
metadata:
  name: partner-payment-secret
type: Opaque
stringData:
  api-key: ${PAYMENT_API_KEY_FROM_VAULT_OR_PIPELINE}

s052: Secret als Volume read-only mounten

Englischer technischer Begriff
Read Only Secret Volume
Priorität
8/10
Warum wichtig
Dateibasierte Secrets sollten nicht schreibbar sein und nicht als normale Konfiguration geloggt werden.
Typischer Fehler
Secret wird als Environment-Variable überall sichtbar.
Enterprise-Einordnung
Relevant für Zertifikate, Tokens, Private Keys und mTLS.
Ausgangspunkt-Code
env:
  - name: CLIENT_PRIVATE_KEY
    value: "-----BEGIN PRIVATE KEY-----..."
Ziel-Code
volumes:
  - name: mtls-client-cert
    secret:
      secretName: partner-mtls-secret
containers:
  - name: order-api
    volumeMounts:
      - name: mtls-client-cert
        mountPath: /var/run/secrets/partner
        readOnly: true

s053: Container als Non-Root starten

Englischer technischer Begriff
Run Container as Non Root
Priorität
9/10
Warum wichtig
Non-Root reduziert Schaden bei Container-Ausbruch oder Schreibfehlern im Dateisystem.
Typischer Fehler
Container läuft als root mit Default-Rechten.
Enterprise-Einordnung
Relevant für OpenShift, Kubernetes, Plattformvorgaben und Security-Reviews.
Ausgangspunkt-Code
containers:
  - name: order-api
    image: registry.example/order-api:latest
Ziel-Code
securityContext:
  runAsNonRoot: true
  allowPrivilegeEscalation: false
  readOnlyRootFilesystem: true
  capabilities:
    drop: ["ALL"]
  seccompProfile:
    type: RuntimeDefault

s054: NetworkPolicy Default-Deny

Englischer technischer Begriff
Kubernetes NetworkPolicy Default Deny
Priorität
9/10
Warum wichtig
Netzwerkzugriff sollte explizit sein. Default-Deny verhindert laterale Bewegung im Cluster.
Typischer Fehler
Alle Pods können alle anderen Pods erreichen.
Enterprise-Einordnung
Relevant für Service-to-Service-Security, Mandantenfähigkeit und Compliance.
Ausgangspunkt-Code
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all
spec:
  podSelector: {}
  ingress:
    - {}
Ziel-Code
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-order-api
spec:
  podSelector:
    matchLabels:
      app: order-api
  policyTypes: [Ingress, Egress]

s055: Egress nur zu erlaubten Partnern

Englischer technischer Begriff
Restricted Egress Policy
Priorität
8/10
Warum wichtig
Ausgehende Verbindungen müssen begrenzt sein, damit SSRF und Fehlkonfiguration nicht beliebige Ziele erreichen.
Typischer Fehler
Pod darf ins gesamte Internet.
Enterprise-Einordnung
Wichtig für Partner-APIs, Payment Provider und interne Legacy-Systeme.
Ausgangspunkt-Code
egress:
  - {}
Ziel-Code
egress:
  - to:
      - namespaceSelector:
          matchLabels:
            name: partner-gateway
    ports:
      - protocol: TCP
        port: 443

s056: Image nicht per latest deployen

Englischer technischer Begriff
Immutable Image Reference
Priorität
8/10
Warum wichtig
latest macht Deployments nicht reproduzierbar und erschwert Incident-Rollback.
Typischer Fehler
Deployment nutzt image: order-api:latest.
Enterprise-Einordnung
Relevant für CI/CD, Rollback, Audit und Change Management.
Ausgangspunkt-Code
image: registry.example/acme/order-api:latest
Ziel-Code
image: registry.example/acme/order-api@sha256:3e7b2c4f0c9d6f1a0b21e9fb8f0ac92bb4e31b4f6d2b7a6c7e34b6ccbe2a1234

s057: Config und Secret fachlich trennen

Englischer technischer Begriff
Config Secret Separation
Priorität
7/10
Warum wichtig
Konfiguration ist nicht automatisch geheim. Secrets brauchen andere Prozesse, Rechte und Rotation.
Typischer Fehler
Alle Werte liegen in einer ConfigMap.
Enterprise-Einordnung
Relevant für OpenShift, GitOps, Helm/Kustomize und Audit.
Ausgangspunkt-Code
apiVersion: v1
kind: ConfigMap
metadata:
  name: order-api-config
data:
  db.password: super-secret
  feature.upload.enabled: "true"
Ziel-Code
apiVersion: v1
kind: ConfigMap
metadata:
  name: order-api-config
data:
  feature.upload.enabled: "true"
---
apiVersion: v1
kind: Secret
metadata:
  name: order-api-db-secret
stringData:
  password: ${DB_PASSWORD_FROM_PIPELINE}

s058: Security Headers am Edge setzen

Englischer technischer Begriff
Security Headers
Priorität
8/10
Warum wichtig
Browser-nahe APIs und Portale brauchen Header gegen Clickjacking, MIME-Sniffing und unsichere Defaults.
Typischer Fehler
Route/Ingress liefert keine Security Header.
Enterprise-Einordnung
Relevant für Portale, API-Gateway, BFF und Downloads.
Ausgangspunkt-Code
return Response.ok(htmlBody);
Ziel-Code
public final class SecurityHeaders {
    public void apply(Response response) {
        response.header("X-Content-Type-Options", "nosniff");
        response.header("X-Frame-Options", "DENY");
        response.header("Referrer-Policy", "no-referrer");
        response.header("Content-Security-Policy", "default-src 'self'; frame-ancestors 'none'");
    }
}
interface Response { void header(String name, String value); }

s059: TLS für Route erzwingen

Englischer technischer Begriff
TLS Termination Policy
Priorität
8/10
Warum wichtig
Externe Kommunikation muss verschlüsselt sein. Unsichere HTTP-Routen dürfen nicht nebenbei bestehen.
Typischer Fehler
Route erlaubt HTTP ohne Redirect.
Enterprise-Einordnung
Relevant für OpenShift Routes, externe Portale und API-Gateway.
Ausgangspunkt-Code
apiVersion: route.openshift.io/v1
kind: Route
spec:
  to:
    kind: Service
    name: order-api
Ziel-Code
apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: order-api
spec:
  to:
    kind: Service
    name: order-api
  tls:
    termination: edge
    insecureEdgeTerminationPolicy: Redirect

s060: Resource Limits gegen DoS setzen

Englischer technischer Begriff
Resource Limits
Priorität
8/10
Warum wichtig
Limits schützen Cluster und Nachbar-Services vor unbegrenztem Speicher- oder CPU-Verbrauch.
Typischer Fehler
Deployment hat keine Requests und Limits.
Enterprise-Einordnung
Relevant für OpenShift-Betrieb, SLOs und Plattformstabilität.
Ausgangspunkt-Code
containers:
  - name: order-api
    image: registry.example/order-api:1.0.0
Ziel-Code
resources:
  requests:
    cpu: 250m
    memory: 512Mi
  limits:
    cpu: "1"
    memory: 1Gi
Audit, Observability und Incident Readiness10 Einträge

Security endet nicht beim Request. Audit, Logs, Metriken, Traces und Runbooks machen Sicherheitsentscheidungen im Betrieb nachvollziehbar.

s061: Audit-Event fachlich strukturieren

Englischer technischer Begriff
Structured Audit Event
Priorität
9/10
Warum wichtig
Audit muss fachlich auswertbar sein: Wer, was, wann, auf welchem Objekt und mit welchem Ergebnis.
Typischer Fehler
Freitext-Log ohne stabile Felder.
Enterprise-Einordnung
Relevant für Revision, Support, Security Operations und Nachweispflichten.
Ausgangspunkt-Code
log.info("user did something with order");
Ziel-Code
import java.time.Instant;

public record AuditEvent(String type, String subject, String tenantId, String objectType, String objectId, String outcome, Instant at) {}

public final class AuditService {
    public void orderCancelled(String subject, String tenantId, String orderId) {
        write(new AuditEvent("ORDER_CANCELLED", subject, tenantId, "Order", orderId, "SUCCESS", Instant.now()));
    }
    private void write(AuditEvent event) { System.out.println(event); }
}

s062: Log Injection verhindern

Englischer technischer Begriff
Log Injection Protection
Priorität
8/10
Warum wichtig
Angreifer können Zeilenumbrüche in Logs einschleusen und Ereignisse fälschen oder verschleiern.
Typischer Fehler
Request-Felder werden ungefiltert ins Log geschrieben.
Enterprise-Einordnung
Relevant für SIEM, Incident-Analyse und Compliance.
Ausgangspunkt-Code
log.info("login failed for " + username);
Ziel-Code
public final class LogSafeValue {
    public String sanitize(String input) {
        return input == null ? "" : input.replaceAll("[\r\n\t]", "_");
    }
}

s063: Security-Metriken erfassen

Englischer technischer Begriff
Security Metrics
Priorität
7/10
Warum wichtig
Metriken zeigen Angriffsmuster, Fehlkonfiguration und Überlast. Sie ergänzen Logs und Traces.
Typischer Fehler
Auth-Fehler verschwinden nur als einzelne Logzeilen.
Enterprise-Einordnung
Relevant für Observability, Alerts und Security Operations.
Ausgangspunkt-Code
catch (AccessDeniedException ex) {
    return Response.forbidden();
}
Ziel-Code
import java.util.concurrent.atomic.AtomicLong;

public final class SecurityMetrics {
    private final AtomicLong denied = new AtomicLong();
    private final AtomicLong tokenFailures = new AtomicLong();
    public void accessDenied() { denied.incrementAndGet(); }
    public void tokenFailed() { tokenFailures.incrementAndGet(); }
    public String snapshot() { return "security_access_denied_total " + denied.get() + "
security_token_failed_total " + tokenFailures.get(); }
}

s064: Trace-Attribute ohne Secrets

Englischer technischer Begriff
Safe Trace Attributes
Priorität
8/10
Warum wichtig
Traces werden breit verteilt. Tokens, Kundendaten oder Zahlungsdaten gehören nicht in Span-Attribute.
Typischer Fehler
Authorization Header wird als Trace-Attribut gespeichert.
Enterprise-Einordnung
Relevant für OpenTelemetry, Jaeger/Tempo, Support und Datenschutz.
Ausgangspunkt-Code
span.setAttribute("http.request.header.authorization", authorizationHeader);
Ziel-Code
span.setAttribute("enduser.id", principal.subjectHash());
span.setAttribute("security.auth.result", "success");
span.setAttribute("tenant.id", principal.tenantId());

s065: Tamper-Evident Audit Hash Chain

Englischer technischer Begriff
Tamper Evident Audit Log
Priorität
7/10
Warum wichtig
Eine Hash-Kette macht nachträgliche Manipulationen erkennbar.
Typischer Fehler
Audit-Events werden überschreibbar gespeichert.
Enterprise-Einordnung
Relevant für Zahlungsfreigaben, Vertragsänderungen und regulierte Prozesse.
Ausgangspunkt-Code
auditRepository.save(event);
Ziel-Code
import java.security.MessageDigest;
import java.util.HexFormat;

public final class AuditHashChain {
    public String nextHash(String previousHash, String canonicalEvent) throws Exception {
        byte[] input = (previousHash + "
" + canonicalEvent).getBytes(java.nio.charset.StandardCharsets.UTF_8);
        return HexFormat.of().formatHex(MessageDigest.getInstance("SHA-256").digest(input));
    }
}

s066: Security-Incident Runbook verlinken

Englischer technischer Begriff
Security Incident Runbook
Priorität
7/10
Warum wichtig
Bei Security-Vorfällen zählt Geschwindigkeit. Logs, Owner, Eskalation und Stop-Schritte müssen bekannt sein.
Typischer Fehler
Fehlerbehandlung beschreibt nur technische Exceptions.
Enterprise-Einordnung
Relevant für Betrieb, SOC, Bereitschaft und Audits.
Ausgangspunkt-Code
## Fehleranalyse
- Log prüfen
- Service neu starten
Ziel-Code
## Security Incident Runbook
1. Correlation-ID und betroffene Tenant-ID sichern.
2. Tokens und API-Keys des Clients sperren.
3. Audit-Events `ACCESS_DENIED`, `TOKEN_REUSE`, `ADMIN_CHANGE` exportieren.
4. Egress zum betroffenen Partner temporär per NetworkPolicy sperren.
5. RCA mit Timeline, Scope und Präventionsmaßnahme dokumentieren.

s067: Audit-Retention bewusst festlegen

Englischer technischer Begriff
Audit Retention Policy
Priorität
7/10
Warum wichtig
Audit-Daten sind nützlich, aber sensibel. Aufbewahrung braucht Zweck, Dauer und Zugriffskontrolle.
Typischer Fehler
Audit wird ewig in normalen Applikationslogs behalten.
Enterprise-Einordnung
Relevant für Datenschutz, Revision und Storage-Kosten.
Ausgangspunkt-Code
audit:
  retentionDays: 9999
  storage: application-log
Ziel-Code
audit:
  retentionDays: 365
  storage: immutable-object-store
  accessRole: security-auditor
  piiMasking: enabled

s068: Anomalien aus Auth-Events ableiten

Englischer technischer Begriff
Authentication Anomaly Detection
Priorität
7/10
Warum wichtig
Viele fehlgeschlagene Logins oder Tokenfehler sind Betriebs- und Angriffssignale.
Typischer Fehler
Auth-Fehler werden nur einzeln betrachtet.
Enterprise-Einordnung
Relevant für SOC, Alerts und API-Schutz.
Ausgangspunkt-Code
if (!validPassword) return Response.unauthorized();
Ziel-Code
public final class AuthAnomalyDetector {
    public boolean suspicious(FailureWindow window) {
        return window.failedLogins() > 20 || window.distinctCountries() > 3 || window.reusedRefreshTokens() > 0;
    }
}
record FailureWindow(int failedLogins, int distinctCountries, int reusedRefreshTokens) {}

s069: Datensparsame Support-Diagnose

Englischer technischer Begriff
Minimal Support Diagnostics
Priorität
6/10
Warum wichtig
Support braucht Kontext, aber nicht zwangsläufig personenbezogene Daten oder Tokens.
Typischer Fehler
Debug-Endpunkt gibt vollständige Request-Header aus.
Enterprise-Einordnung
Relevant für Produktivsupport, Admin-Portale und Fehlerdiagnose.
Ausgangspunkt-Code
return request.headers().toString();
Ziel-Code
public final class SupportDiagnostics {
    public DiagnosticView view(Request request) {
        return new DiagnosticView(request.correlationId(), request.tenantId(), request.route(), request.status());
    }
}
record Request(String correlationId, String tenantId, String route, int status) {}
record DiagnosticView(String correlationId, String tenantId, String route, int status) {}

s070: Security Events mit Correlation-ID verbinden

Englischer technischer Begriff
Correlated Security Events
Priorität
7/10
Warum wichtig
Ein Security-Vorfall besteht aus vielen Events. Correlation-ID verbindet API, Audit, Trace und Logs.
Typischer Fehler
Audit-Events enthalten keine technische Korrelation.
Enterprise-Einordnung
Relevant für verteilte Systeme, Partnerfälle und Incident-Analyse.
Ausgangspunkt-Code
audit.record("ORDER_EXPORT_DENIED", user);
Ziel-Code
audit.record(new AuditEvent(
    "ORDER_EXPORT_DENIED",
    principal.subject(),
    principal.tenantId(),
    request.correlationId(),
    java.time.Instant.now()
));
record AuditEvent(String type, String subject, String tenantId, String correlationId, java.time.Instant at) {}
Security Testing, Maven Gates und Supply Chain10 Einträge

Diese Kategorie macht Security automatisierbar: Build-Gates, SBOM, Secret-Scanning, Tests, Container-Scanning und Regression.

s071: Dependency Vulnerability Gate im Maven-Build

Englischer technischer Begriff
Dependency Vulnerability Gate
Priorität
9/10
Warum wichtig
Bekannte Schwachstellen in Dependencies müssen automatisiert auffallen, nicht zufällig im Review.
Typischer Fehler
Dependencies werden nur funktional gebaut.
Enterprise-Einordnung
Relevant für Maven-Projekte, CI/CD, Release-Gates und Audits.
Ausgangspunkt-Code
<dependency>
  <groupId>com.legacy</groupId>
  <artifactId>legacy-json</artifactId>
  <version>1.0</version>
</dependency>
Ziel-Code
<plugin>
  <groupId>org.owasp</groupId>
  <artifactId>dependency-check-maven</artifactId>
  <version>10.0.4</version>
  <configuration>
    <failBuildOnCVSS>7.0</failBuildOnCVSS>
    <formats>HTML,JSON</formats>
  </configuration>
</plugin>

s072: SBOM für Lieferkette erzeugen

Englischer technischer Begriff
Software Bill of Materials
Priorität
8/10
Warum wichtig
Eine SBOM macht nachvollziehbar, welche Komponenten in einem Release enthalten sind.
Typischer Fehler
Im Incident ist unbekannt, welche Version einer Bibliothek produktiv läuft.
Enterprise-Einordnung
Relevant für Supply Chain, Compliance, OpenShift Images und Incident Response.
Ausgangspunkt-Code
<build>
  <plugins>
    <!-- keine Komponentenliste -->
  </plugins>
</build>
Ziel-Code
<plugin>
  <groupId>org.cyclonedx</groupId>
  <artifactId>cyclonedx-maven-plugin</artifactId>
  <version>2.8.0</version>
  <executions>
    <execution>
      <phase>package</phase>
      <goals><goal>makeAggregateBom</goal></goals>
    </execution>
  </executions>
</plugin>

s073: Secrets in CI blockieren

Englischer technischer Begriff
Secret Scanning Gate
Priorität
9/10
Warum wichtig
Secrets dürfen nicht durch Pull Requests, Artefakte oder Logs in die Pipeline gelangen.
Typischer Fehler
CI baut auch Commits mit Private Keys oder Tokens.
Enterprise-Einordnung
Relevant für GitHub Actions, Jenkins, GitLab, Maven und OpenShift Deployments.
Ausgangspunkt-Code
steps:
  - run: mvn package
  - run: oc apply -f deploy/openshift
Ziel-Code
steps:
  - name: Secret scan
    run: |
      if grep -R --line-number -E "(BEGIN PRIVATE KEY|AKIA[0-9A-Z]{16}|password=.+)" .; then
        echo "Potential secret found" >&2
        exit 1
      fi
  - name: Maven verify
    run: mvn -B verify

s074: Security Header Test automatisieren

Englischer technischer Begriff
Security Header Test
Priorität
8/10
Warum wichtig
Security Headers verschwinden leicht durch Proxy- oder Framework-Änderungen. Ein Test hält sie sichtbar.
Typischer Fehler
Headers werden manuell im Browser geprüft.
Enterprise-Einordnung
Relevant für Portale, BFF, APIs und Edge-Konfiguration.
Ausgangspunkt-Code
assert response.statusCode() == 200;
Ziel-Code
import java.net.URI;
import java.net.http.*;

public final class SecurityHeaderCheck {
    public void assertHeaders(URI uri) throws Exception {
        HttpResponse<String> response = HttpClient.newHttpClient().send(
            HttpRequest.newBuilder(uri).GET().build(), HttpResponse.BodyHandlers.ofString());
        require(response.headers().firstValue("X-Content-Type-Options").orElse(""), "nosniff");
        require(response.headers().firstValue("X-Frame-Options").orElse(""), "DENY");
    }
    private void require(String actual, String expected) { if (!expected.equals(actual)) throw new AssertionError(actual); }
}

s075: Autorisierungsmatrix testen

Englischer technischer Begriff
Authorization Matrix Test
Priorität
9/10
Warum wichtig
Berechtigungen müssen als Matrix testbar sein: Rolle, Aktion, Objekt, Mandant, erwartetes Ergebnis.
Typischer Fehler
Es gibt nur Happy-Path-Tests mit Admin-Rechten.
Enterprise-Einordnung
Relevant für Regression, Audits und Rollenmodell-Änderungen.
Ausgangspunkt-Code
assert policy.canCancel(admin, order);
Ziel-Code
public final class AuthorizationMatrixTest {
    public void checksTenantBoundary() {
        OrderPolicy policy = new OrderPolicy();
        User manager = new User("tenant-a", java.util.Set.of("order:cancel"));
        assert policy.canCancel(manager, new Order("O-1", "tenant-a"));
        assert !policy.canCancel(manager, new Order("O-2", "tenant-b"));
    }
}
record User(String tenantId, java.util.Set<String> permissions) {}
record Order(String id, String tenantId) {}
class OrderPolicy { boolean canCancel(User u, Order o){ return u.permissions().contains("order:cancel") && u.tenantId().equals(o.tenantId()); } }

s076: Upload-Security testen

Englischer technischer Begriff
Upload Security Test
Priorität
8/10
Warum wichtig
Upload-Validierung braucht Tests für Traversal, Größe, Typen und gefährliche Inhalte.
Typischer Fehler
Es wird nur ein gültiger CSV-Upload getestet.
Enterprise-Einordnung
Relevant für Dokumentenportale, CSV-Import und Partner-Dateien.
Ausgangspunkt-Code
uploadService.accept("orders.csv", validBytes);
Ziel-Code
public final class UploadSecurityTest {
    public void rejectsTraversalName() {
        UploadPolicy policy = new UploadPolicy();
        assertThrows(SecurityException.class, () -> policy.requireSafeName("../../secret.txt"));
    }
    private void assertThrows(Class<? extends Throwable> type, Runnable action) {
        try { action.run(); throw new AssertionError("expected " + type.getName()); }
        catch (Throwable t) { if (!type.isInstance(t)) throw new AssertionError(t); }
    }
}
class UploadPolicy { void requireSafeName(String n){ if(n.contains("..") || n.contains("/")) throw new SecurityException(); } }

s077: Security Context Leak in Concurrency testen

Englischer technischer Begriff
Security Context Leak Test
Priorität
8/10
Warum wichtig
ThreadLocal-Security-Kontexte können bei ExecutorService oder Pools zum falschen Benutzer durchrutschen.
Typischer Fehler
Tests laufen nur synchron im selben Thread.
Enterprise-Einordnung
Relevant für Async, ExecutorService, CompletableFuture und Virtual Threads.
Ausgangspunkt-Code
SecurityContext.set(new Principal("alice"));
executor.submit(() -> service.doWork());
Ziel-Code
import java.util.concurrent.*;

public final class SecurityContextLeakTest {
    public void contextMustBeExplicit() throws Exception {
        ExecutorService executor = Executors.newFixedThreadPool(1);
        Principal bob = new Principal("bob");
        Future<String> result = executor.submit(() -> new SecuredJob().runAs(bob));
        assert "bob".equals(result.get());
        executor.shutdown();
    }
}
record Principal(String subject) {}
class SecuredJob { String runAs(Principal p){ return p.subject(); } }

s078: SAST-Ergebnis als Quality Gate behandeln

Englischer technischer Begriff
Static Analysis Security Gate
Priorität
7/10
Warum wichtig
Statische Analyse findet wiederkehrende Fehlerklassen früh, bevor sie in Artefakte gelangen.
Typischer Fehler
SAST-Berichte werden erzeugt, aber nie bewertet.
Enterprise-Einordnung
Relevant für große Teams, Compliance und Security Champions.
Ausgangspunkt-Code
- name: Build
  run: mvn -B package
Ziel-Code
- name: Static security analysis
  run: mvn -B -Psecurity verify
- name: Fail on high findings
  run: |
    test ! -f target/security/high-findings.txt

s079: Container Image Scan vor Deployment

Englischer technischer Begriff
Container Image Scan Gate
Priorität
8/10
Warum wichtig
Der fertige Container enthält Betriebssystempakete und JVM-Schichten, nicht nur Maven-Dependencies.
Typischer Fehler
Nur der Maven-Build wird geprüft, das Image nicht.
Enterprise-Einordnung
Relevant für OpenShift, Registry, Release-Freigabe und Betriebsrisiko.
Ausgangspunkt-Code
- run: docker build -t registry.example/order-api:${GIT_SHA} .
- run: oc rollout restart deployment/order-api
Ziel-Code
- run: docker build -t registry.example/order-api:${GIT_SHA} .
- run: trivy image --exit-code 1 --severity HIGH,CRITICAL registry.example/order-api:${GIT_SHA}
- run: oc set image deployment/order-api order-api=registry.example/order-api:${GIT_SHA}

s080: Security Regression Suite in Release-Pipeline

Englischer technischer Begriff
Security Regression Suite
Priorität
9/10
Warum wichtig
Security darf nicht nur Projektphase sein. Kritische Regeln müssen bei jedem Release laufen.
Typischer Fehler
Manuelle Security-Checkliste kurz vor Go-Live.
Enterprise-Einordnung
Relevant für Release-Zyklen, Plattformteams und langfristige Wartung.
Ausgangspunkt-Code
stages:
  - build
  - deploy
Ziel-Code
stages:
  - build
  - unit-test
  - security-test
  - sbom
  - image-scan
  - deploy-staging
  - smoke-security
  - promote
⌂ Cockpit