J2EE Bad Practices: Direkte Verwendung von Threads

Beschreibung

J2EE Bad Practices: Direkte Verwendung von Threads ist eine Schwachstelle, die auftritt, wenn eine Webanwendung direkt Threads erstellt und verwaltet, anstatt container-verwaltete Konkurrenz zu verwenden. Thread-Management in einer Webanwendung ist unter bestimmten Umständen verboten (insbesondere in EJBs) und ist immer höchst fehleranfällig. Direktes Thread-Management riskiert eine unvorhersehbare Beeinflussung des Container-Verhaltens und produziert häufig schwer zu diagnostizierende Probleme wie Deadlocks, Race Conditions und Synchronisationsfehler.

Risiko

Direktes Thread-Management in J2EE-Anwendungen verletzt Container-Verträge und erzeugt unvorhersehbares Verhalten. Der Container kann Ressourcen nicht ordnungsgemäß verwalten, wenn Anwendungscode seine eigenen Threads erstellt, was potenziell zu Ressourcenerschöpfung führt. Threads, die außerhalb der Kontrolle des Containers erstellt werden, können während des Container-Shutdowns Ressourcen halten, was zu Hängen oder Datenkorruption führt. Race Conditions und Deadlocks werden wahrscheinlicher und schwerer zu debuggen. Der Thread-Lebenszyklus stimmt nicht mit dem Request-Lebenszyklus überein, was Fehlerbehandlung und Ressourcenbereinigung kompliziert. In geclusterten Umgebungen kann direktes Threading inkonsistentes Verhalten über Knoten hinweg verursachen.

Lösung

Verwenden Sie framework-bereitgestellte Mechanismen für parallele Ausführung. In EJB-Umgebungen verwenden Sie den EJB Timer Service, @Asynchronous-Methoden oder ManagedExecutorService. In Spring verwenden Sie @Async mit ordnungsgemäßer Executor-Konfiguration. Verwenden Sie die Java EE Concurrency Utilities (JSR 236), die ManagedExecutorService, ManagedScheduledExecutorService und ManagedThreadFactory bereitstellen. Diese container-verwalteten Ressourcen integrieren sich ordnungsgemäß mit Transaktionsmanagement, Sicherheitskontext-Propagierung und Ressourcen-Lebenszyklus. Wenn Legacy-Threading-Code existiert, refaktorieren Sie zu ExecutorService mit ordnungsgemäßer Shutdown-Behandlung.

Häufige Auswirkungen

AuswirkungDetails
AndereUmfang: Ändere

Qualitätsverschlechterung - Die Schwäche beeinflusst negativ die Zuverlässigkeit und Stabilität der Anwendung durch unvorhersehbares Threading-Verhalten.

Beispielcode

Anfälliger Code

// Anfällig: Direkte Thread-Erstellung in Servlet
public class VulnerableServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request,
                         HttpServletResponse response)
                         throws ServletException, IOException {
        final String data = request.getParameter("data");

        // Anfällig: Thread direkt erstellen
        Thread worker = new Thread(new Runnable() {
            public void run() {
                // Hintergrundverarbeitung
                processData(data);
            }
        });
        worker.start();

        response.getWriter().write("Verarbeitung gestartet");
    }
}

// Anfällig: Raw Thread in EJB verwenden
@Stateless
public class VulnerableEJB {

    public void processAsync(final String input) {
        // Anfällig: EJBs dürfen keine Threads erstellen
        new Thread(() -> {
            heavyProcessing(input);
        }).start();
    }

    public void scheduledTask() {
        // Anfällig: Benutzerdefinierter Thread für Scheduling
        Thread scheduler = new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(60000);
                    runPeriodicTask();
                } catch (InterruptedException e) {
                    break;
                }
            }
        });
        scheduler.setDaemon(true);
        scheduler.start();
    }
}

// Anfällig: Thread-Pool nicht vom Container verwaltet
@WebServlet("/process")
public class VulnerablePoolServlet extends HttpServlet {
    // Anfällig: Statischer Thread-Pool außerhalb Container-Kontrolle
    private static ExecutorService executor =
        Executors.newFixedThreadPool(10);

    protected void doPost(HttpServletRequest request,
                          HttpServletResponse response) {
        executor.submit(() -> processRequest(request));
    }
    // Keine ordnungsgemäße Shutdown-Behandlung!
}

Korrigierter Code

// Korrigiert: ManagedExecutorService verwenden (Java EE 7+)
@WebServlet("/process")
public class SecureServlet extends HttpServlet {

    @Resource
    private ManagedExecutorService executor;

    protected void doGet(HttpServletRequest request,
                         HttpServletResponse response)
                         throws ServletException, IOException {
        final String data = request.getParameter("data");

        // Korrigiert: Container-verwalteter Executor
        executor.submit(() -> processData(data));

        response.getWriter().write("Verarbeitung gestartet");
    }
}

// Korrigiert: @Asynchronous in EJB verwenden
@Stateless
public class SecureEJB {

    @Asynchronous
    public Future<String> processAsync(String input) {
        // Korrigiert: Container verwaltet den Thread
        String result = heavyProcessing(input);
        return new AsyncResult<>(result);
    }

    @Resource
    private TimerService timerService;

    @PostConstruct
    public void init() {
        // Korrigiert: Timer-Service des Containers verwenden
        timerService.createIntervalTimer(60000, 60000,
            new TimerConfig("periodicTask", false));
    }

    @Timeout
    public void runPeriodicTask(Timer timer) {
        // Container verwaltet Scheduling
        performScheduledWork();
    }
}

// Korrigiert: ManagedThreadFactory verwenden
@WebServlet("/managed")
public class SecureManagedServlet extends HttpServlet {

    @Resource
    private ManagedThreadFactory threadFactory;

    @Resource
    private ManagedExecutorService executor;

    protected void doPost(HttpServletRequest request,
                          HttpServletResponse response) {
        // Korrigiert: Container-verwaltete Thread-Factory
        Runnable task = () -> processRequest(request);
        executor.submit(task);
    }
}

// Korrigiert: Spring @Async mit ordnungsgemäßer Konfiguration
@Service
public class SecureSpringService {

    @Async("taskExecutor")  // Verwendet konfigurierten Executor
    public CompletableFuture<String> processAsync(String input) {
        String result = heavyProcessing(input);
        return CompletableFuture.completedFuture(result);
    }
}

@Configuration
@EnableAsync
public class AsyncConfig {

    @Bean("taskExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("async-");
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(30);
        executor.initialize();
        return executor;
    }
}

// Korrigiert: Ordnungsgemäßer Executor-Lebenszyklus im Servlet-Kontext
@WebListener
public class ExecutorLifecycleListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        // Initialisierung vom Container behandelt
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        // Korrigiert: Ordnungsgemäßer Shutdown wenn benutzerdefinierter Executor verwendet wird
        ExecutorService executor =
            (ExecutorService) sce.getServletContext().getAttribute("executor");
        if (executor != null) {
            executor.shutdown();
            try {
                if (!executor.awaitTermination(30, TimeUnit.SECONDS)) {
                    executor.shutdownNow();
                }
            } catch (InterruptedException e) {
                executor.shutdownNow();
            }
        }
    }
}

CVE-Beispiele

Keine spezifischen CVEs sind für diese CWE gelistet. Das Schwachstellenmuster erscheint in:

  • J2EE-Anwendungen, die rohe Thread-Erstellung verwenden
  • EJBs, die Threading-Beschränkungen verletzen
  • Webanwendungen mit unverwalteten Thread-Pools

Referenzen

  1. MITRE Corporation. "CWE-383: J2EE Bad Practices: Direct Use of Threads." https://cwe.mitre.org/data/definitions/383.html
  2. Java EE 7 Tutorial. "Concurrency Utilities for Java EE."