EJB Bad Practices: Use of AWT/Swing

Description

EJB Bad Practices: Use of AWT/Swing is a vulnerability where an Enterprise JavaBean violates the EJB specification by incorporating AWT (Abstract Window Toolkit) or Swing GUI functionality. The EJB specification explicitly prohibits bean providers from using "AWT functionality to attempt to output information to a display, or to input information from a keyboard." EJBs are designed to handle business logic in server-side environments where no display or keyboard interaction is available. Attempting to use GUI components in this context results in failures, as server systems typically run headless without access to display devices.

Risk

Using AWT/Swing in EJBs creates immediate operational failures and architectural violations. In headless server environments, GUI operations throw HeadlessException, causing runtime failures. Even if a server has display capability, GUI operations block threads waiting for user input that never comes, causing application hangs. The design violates the separation of concerns principle—mixing presentation logic with business logic makes code non-reusable and difficult to maintain. Applications become non-portable across different deployment environments. Container management of bean lifecycle becomes problematic when beans hold GUI resources.

Solution

Never use AWT or Swing components in EJB implementations. Follow the Model-View-Controller (MVC) pattern, keeping EJBs strictly as the model layer containing business logic. Use web tier technologies (JSP, JSF, Servlets) or dedicated client applications for presentation. If EJBs need to provide data for display, return data transfer objects (DTOs) that the presentation layer can render. For reporting or document generation, use server-side libraries that don't require a display (like Apache POI for Excel, iText for PDF). If absolutely necessary to perform graphical operations, use headless mode with BufferedImage.

Common Consequences

ImpactDetails
OtherScope: Other

Quality Degradation - Applications fail to function correctly when GUI operations cannot be performed in server environments.
AvailabilityScope: Availability

DoS: Crash, Exit, or Restart - GUI operations in headless environments throw exceptions, potentially crashing the application.

Example Code

Vulnerable Code

// Vulnerable: EJB using AWT/Swing components
import javax.ejb.Stateless;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

@Stateless
public class VulnerableReportBean implements ReportService {

    // Vulnerable: Creating AWT Frame in EJB
    public void displayReport(ReportData data) {
        // This will fail in headless server environment
        Frame frame = new Frame("Report");  // HeadlessException!
        frame.setSize(800, 600);

        TextArea textArea = new TextArea();
        textArea.setText(data.toString());
        frame.add(textArea);

        frame.setVisible(true);  // No display available on server!
    }
}

// Vulnerable: Stateless bean extending Component
@Stateless
public class VulnerableInputBean extends Component implements KeyListener {

    // Vulnerable: Implementing KeyListener in EJB
    @Override
    public void keyPressed(KeyEvent e) {
        // No keyboard input available on server
        processKey(e.getKeyCode());
    }

    @Override
    public void keyReleased(KeyEvent e) { }

    @Override
    public void keyTyped(KeyEvent e) { }

    // Vulnerable: Attempting to capture keyboard input
    public String getUserInput() {
        // This makes no sense in server context
        TextField input = new TextField();  // HeadlessException!
        input.addKeyListener(this);
        // Will never receive input
        return input.getText();
    }
}

// Vulnerable: Using Swing in EJB
@Stateless
public class VulnerableDialogBean implements DialogService {

    // Vulnerable: Creating Swing dialog in EJB
    public boolean confirmAction(String message) {
        // This will fail on headless server
        int result = JOptionPane.showConfirmDialog(
            null,
            message,
            "Confirm",
            JOptionPane.YES_NO_OPTION
        );  // HeadlessException in server environment!

        return result == JOptionPane.YES_OPTION;
    }

    // Vulnerable: Creating Swing frame
    public void showStatus(String status) {
        JFrame frame = new JFrame("Status");  // HeadlessException!
        JLabel label = new JLabel(status);
        frame.add(label);
        frame.pack();
        frame.setVisible(true);  // No display!
    }
}

// Vulnerable: Using Graphics for image processing incorrectly
@Stateless
public class VulnerableImageBean implements ImageService {

    // Vulnerable: Creating window for graphics
    public byte[] createChart(ChartData data) {
        // Vulnerable: Requires display context
        Frame frame = new Frame();  // HeadlessException!
        frame.addNotify();

        Image image = frame.createImage(400, 300);
        Graphics g = image.getGraphics();

        // Draw chart
        g.drawRect(0, 0, 399, 299);
        // ... more drawing

        g.dispose();
        return convertToBytes(image);
    }
}

Fixed Code

// Fixed: EJB returns data, presentation layer handles display
import javax.ejb.Stateless;
import java.util.List;

@Stateless
public class SecureReportBean implements ReportService {

    @PersistenceContext
    private EntityManager em;

    // Fixed: Return data for presentation layer to display
    public ReportDTO getReport(Long reportId) {
        // Business logic only - no GUI
        Report report = em.find(Report.class, reportId);

        // Return DTO for presentation layer
        ReportDTO dto = new ReportDTO();
        dto.setTitle(report.getTitle());
        dto.setData(report.getData());
        dto.setGeneratedDate(new Date());

        return dto;
    }

    // Fixed: Generate report as bytes for download
    public byte[] generatePdfReport(Long reportId) {
        Report report = em.find(Report.class, reportId);

        // Use server-side PDF library (no GUI required)
        return PdfGenerator.createReport(report);
    }
}

// Fixed: Use JSP/JSF for presentation, EJB for logic
// JSF Managed Bean (presentation layer)
@Named
@ViewScoped
public class ReportController implements Serializable {

    @Inject
    private ReportService reportService;  // EJB

    private ReportDTO currentReport;

    public void loadReport(Long reportId) {
        // Get data from EJB
        currentReport = reportService.getReport(reportId);
    }

    public ReportDTO getCurrentReport() {
        return currentReport;
    }
}

// Fixed: Separate presentation logic from business logic
// EJB handles business logic only
@Stateless
public class SecureInputBean implements InputService {

    // Fixed: No keyboard input - receive data as parameters
    public ProcessResult processUserInput(UserInputDTO input) {
        // Validate input received from presentation layer
        validateInput(input);

        // Process business logic
        ProcessResult result = new ProcessResult();
        result.setProcessedValue(calculate(input.getValue()));
        result.setTimestamp(new Date());

        return result;
    }

    private void validateInput(UserInputDTO input) {
        if (input == null || input.getValue() == null) {
            throw new ValidationException("Input required");
        }
    }
}

// Fixed: Use headless mode for server-side image generation
import java.awt.image.BufferedImage;
import java.awt.Graphics2D;
import java.awt.Color;
import javax.imageio.ImageIO;

@Stateless
public class SecureImageBean implements ImageService {

    // Fixed: Use BufferedImage - works in headless mode
    public byte[] createChart(ChartData data) {
        // Ensure headless mode (usually set at JVM startup)
        // -Djava.awt.headless=true

        // Create image without display
        BufferedImage image = new BufferedImage(
            400, 300, BufferedImage.TYPE_INT_RGB);

        Graphics2D g = image.createGraphics();

        // Draw chart
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, 400, 300);
        g.setColor(Color.BLACK);
        g.drawRect(0, 0, 399, 299);

        // Draw data
        drawChartData(g, data);

        g.dispose();

        // Convert to bytes
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            ImageIO.write(image, "PNG", baos);
        } catch (IOException e) {
            throw new RuntimeException("Image generation failed", e);
        }

        return baos.toByteArray();
    }

    private void drawChartData(Graphics2D g, ChartData data) {
        // Server-side chart rendering logic
    }
}

// Fixed: Use server-side charting library
import org.jfree.chart.JFreeChart;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;

@Stateless
public class SecureChartBean implements ChartService {

    // Fixed: Use JFreeChart (works headless)
    public byte[] createBarChart(ChartDataDTO data) {
        // JFreeChart works in headless mode
        JFreeChart chart = ChartFactory.createBarChart(
            data.getTitle(),
            data.getCategoryLabel(),
            data.getValueLabel(),
            createDataset(data),
            PlotOrientation.VERTICAL,
            true,  // legend
            true,  // tooltips
            false  // urls
        );

        // Export to PNG bytes
        try {
            return ChartUtilities.encodeAsPNG(
                chart.createBufferedImage(600, 400));
        } catch (IOException e) {
            throw new RuntimeException("Chart generation failed", e);
        }
    }
}

// Fixed: Web service endpoint for remote clients
@Stateless
@WebService
public class SecureReportWebService {

    @Inject
    private ReportService reportService;

    // Fixed: SOAP/REST service returns data, client renders
    @WebMethod
    public ReportDTO getReport(@WebParam(name="reportId") Long reportId) {
        return reportService.getReport(reportId);
    }

    @WebMethod
    public byte[] getReportPdf(@WebParam(name="reportId") Long reportId) {
        return reportService.generatePdfReport(reportId);
    }
}

CVE Examples

No specific CVEs are commonly attributed to this CWE, as it primarily affects application functionality rather than security vulnerabilities.


References

  1. MITRE Corporation. "CWE-575: EJB Bad Practices: Use of AWT Swing." https://cwe.mitre.org/data/definitions/575.html
  2. Oracle. "Enterprise JavaBeans Specification."
  3. Oracle. "Java Headless Mode Documentation."