5 Common Jakarta EE Security Issues and Solutions

Jakarta EE applications might be vulnerable to serious security risks, but you can protect them by addressing these five common issues:

  1. Authentication Flaws: Weak passwords, poor session management, and insecure credential storage are common. Use the Jakarta Security API to enforce strong authentication mechanisms like OpenID Connect and secure identity stores.
  2. Access Control Gaps: Misconfigured roles, unprotected endpoints, and token mismanagement can lead to unauthorized access. Implement Role-Based Access Control (RBAC) using annotations like @RolesAllowed and monitor access violations.
  3. Cross-Site Scripting (XSS): XSS attacks exploit unvalidated inputs to inject malicious scripts. Use input validation, output encoding, and Content Security Policies (CSP) to block harmful code.
  4. Data Storage and Transfer Security: Risks like unencrypted data and hardcoded keys can be mitigated by enforcing HTTPS, using secure storage tools, and applying encryption for sensitive data.
  5. Injection Attacks: SQL, XML, and LDAP injection attacks exploit unvalidated inputs. Prevent them with parameterized queries, input validation, and the Jakarta Criteria API for safe database access.

Quick Tip: Regularly update GlassFish or your Jakarta EE server or runtime of choice, keep your application dependencies updated, monitor vulnerabilities, and use Jakarta EE’s built-in security features to stay ahead of threats.

These steps ensure your applications remain secure while safeguarding sensitive data and user trust.

1. Fixing Authentication Issues

Common Authentication Weaknesses

Jakarta EE applications often face authentication vulnerabilities due to poor security practices. Some typical issues include:

  • Weak password policies that make credentials easy to guess
  • Poor session management, which can lead to session hijacking
  • Reliance on single-factor authentication, offering minimal protection
  • Storing credentials insecurely with outdated hashing methods
  • Misconfigured or missing identity stores

Setting Up Strong Authentication

The Jakarta Security API provides built-in authentication features that work seamlessly with Jakarta CDI, eliminating the need for vendor-specific configurations [1].

Here’s how to set up authentication:

  1. Define Security Constraints. Use the following XML snippet to protect specific HTTP resources:
    • <security-constraint>
      <web-resource-collection>
      <web-resource-name>Protected Area</web-resource-name>
      <url-pattern>/secure/*</url-pattern>
      </web-resource-collection>
      <auth-constraint>
      <role-name>ADMIN</role-name>
      </auth-constraint>
      </security-constraint>
  2. Choose an Authentication Mechanism. Options include:
    • Basic Authentication
    • Form-based Authentication
    • Custom Form Authentication
    • OpenID Connect (OIDC)
  3. Set Up an Identity Store. Configure an identity store to validate user credentials against a database or LDAP directory.

Example: Jakarta Security Implementation

Here’s an example of how to implement authentication using Jakarta Security. This example defines getting user’s credentials using a HTML form and validating them using hashed passwords and roles stored in the database:

@DatabaseIdentityStoreDefinition(
    dataSourceLookup = "jdbc/UserDS",
    callerQuery = "SELECT password FROM users WHERE username = ?",
    groupsQuery = "SELECT role FROM user_roles WHERE username = ?"
)
@FormAuthenticationMechanismDefinition(
    loginToContinue = @LoginToContinue(
        loginPage = "/login.html",
        errorPage = "/error.html"
    )
)
@ApplicationScoped
public class SecurityConfig {

    @Inject
    private SecurityContext securityContext;

    public boolean isUserInRole(String role) {
        return securityContext.isCallerInRole(role);
    }
}

This setup provides several advantages:

If multiple identity stores are configured, the Jakarta Security API prioritizes them automatically, offering flexible yet secure authentication options [1].

Eclipse GlassFish is a Fast, Updated and Secure OpenSource Jakarta EE Server supported by OmniFish.

Find out more about its progress and current state in 2024 in this article: GlassFish is rolling forward. What’s New?

Next, we’ll discuss how to address access control issues to further enhance the security of Jakarta EE applications.

2. Fixing Access Control Gaps

Access Control Weaknesses

Jakarta EE applications often face issues with access control [2]. Some common problems include:

  • Improper Role Management: Roles are misconfigured, granting more permissions than necessary.
  • Unprotected Endpoints: REST endpoints lack adequate security measures.
  • Insufficient Access Verification: Applications fail to confirm if users have ownership of the resources they’re accessing.
  • Missing Rate Limiting: Automated attacks aren’t mitigated due to the absence of rate limits.
  • Token Mismanagement: Tokens, such as JWTs, aren’t invalidated after logout.

For instance, an attacker can exploit a poorly verified SQL parameter to access restricted data:

// Vulnerable code
pstmt.setString(1, request.getParameter("acct"));
ResultSet results = pstmt.executeQuery();

By altering the URL parameter like this: http://example.com/app/accountInfo?acct=notmyacct, the attacker can gain unauthorized access [2].

To address such vulnerabilities, you can leverage Jakarta EE’s built-in access control features.

Setting Up Access Controls

Strong access control, when paired with robust authentication, is key to securing a Jakarta EE application. Jakarta EE provides both declarative and programmatic Role-Based Access Control (RBAC) [3].

Here’s an example of declarative access control:

@DeclareRoles({"ADMIN", "USER"})
@WebServlet("/secure/data")
public class SecureServlet extends HttpServlet {

    @Inject
    private SecurityContext securityContext;

    @RolesAllowed("ADMIN")
    protected void doGet(HttpServletRequest request,
                        HttpServletResponse response) {
        // Accessible to ADMINs only
        if (securityContext.isCallerInRole("ADMIN")) {
            // Process admin request
        }
    }
}

Access Control Setup Steps

To secure your application, follow these steps:

  1. Define Security Constraints

Use XML to define constraints for specific resources:

<security-constraint>
    <web-resource-collection>
        <web-resource-name>Admin Resources</web-resource-name>
        <url-pattern>/admin/*</url-pattern>
        <http-method>GET</http-method>
        <http-method>POST</http-method>
    </web-resource-collection>
    <auth-constraint>
        <role-name>ADMIN</role-name>
    </auth-constraint>
</security-constraint>
  1. Implement Role-Based Security

Control access to methods using annotations:

@Stateless
public class DataService {

    @RolesAllowed("USER")
    public List<Data> getUserData() {
        // Accessible to USERs only
        return dataRepository.findUserData();
    }

    @DenyAll
    public void restrictedOperation() {
        // No access permitted
    }
}
  1. Configure Access Control Monitoring

Monitor and log access violations with a filter:

@WebFilter("/*")
public class SecurityAuditFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request,
                        ServletResponse response,
                        FilterChain chain) {
        try {
            chain.doFilter(request, response);
        } catch (AccessControlException e) {
            logger.warning("Access control violation: " + e.getMessage());
            // Notify administrators
        }
    }
}

These steps help ensure your application is protected against unauthorized access while maintaining proper role-based permissions.

3. Stopping XSS Attacks

How XSS Affects Jakarta EE

XSS poses a serious threat to all web applications by embedding harmful client-side code into web pages. This makes having strong defense mechanisms a must.

Here are the main types of XSS attacks that can impact Jakarta EE applications:

Attack TypeTargetImpact
Stored XSSServer-side storageMalicious code gets saved on the server (e.g., in a database) and affects all users accessing the infected content.
Reflected XSSServer responseHarmful code is instantly reflected off the server when a user clicks on a manipulated link.
DOM-based XSSClient browserExploits client-side JavaScript to alter the DOM without involving the server.
Mutated XSSBrowser parsingCode initially appearing safe is modified during browser parsing, making it dangerous.

XSS Protection Methods

Defending against XSS requires a multi-layered approach, starting with strict input validation and using output encoding tailored to the context [4].

Some key strategies include:

  • Enforcing server-side input validation
  • Implementing context-aware output encoding
  • Enabling a Content Security Policy (CSP)
  • Using secure template engines that escape output automatically
  • Leveraging established validation frameworks

The OWASP ESAPI framework provides a range of tools for security, while Jakarta Validation (formerly JSR 303) simplifies server-side input validation with annotations [4].

“Whitelisting is the preferred and recommended approach because it is impossible to know all the dangerous input values as newer attack vectors are developed” [4]

Here’s an example of these techniques in action.

Input Validation Example

Below is a practical example of protecting against XSS in a Jakarta EE application:

@WebServlet("/secure/comment")
public class SecureCommentServlet extends HttpServlet {

    @Inject
    private ValidationService validator;

    protected void doPost(HttpServletRequest request,
                          HttpServletResponse response) throws IOException {

        String userInput = request.getParameter("comment");

        // Step 1: Input Validation, e.g. using Jakarta Validation annotations
        if (!validator.isValidInput("Comment", userInput, "SafeText", 1000, false)) {
            response.sendError(400, "Invalid input detected");
            return;
        }

        // Step 2: Canonicalization using OWASP ESAPI component 
        String canonicalInput = ESAPI.encoder().canonicalize(userInput);

        // Step 3: Output Encoding using OWASP ESAPI component
        String safeOutput = ESAPI.encoder().encodeForHTML(canonicalInput);

        response.getWriter().write(safeOutput);
    }
}

When working with template engines like Thymeleaf or Jakarta Faces (formerly JSF), always use secure attributes that escape output automatically.

Example with Jakarta Faces (JSF):

<!-- Safe: Escapes output automatically -->
<h:outputText value="#{userComment}"/>

<!-- Unsafe: Allows unescaped HTML -->
<span>${userComment}</span>

<!-- Unsafe: Allows unescaped HTML -->
<h:outputText value="#{userComment}" escape="false" />

Example with Thymeleaf:

<!-- Safe: Escapes output automatically -->
<div th:text="${userComment}"></div>

<!-- Unsafe: Allows unescaped HTML -->
<div th:utext="${userComment}"></div>

To further enhance security, include the following headers in your Jakarta EE application, for example using a servlet filter:

response.setHeader("Content-Security-Policy", "default-src 'self'; script-src 'self'");
response.setHeader("X-XSS-Protection", "1; mode=block");
response.setHeader("X-Content-Type-Options", "nosniff");

4. Securing Data Storage and Transfer

Data Security Risks

Jakarta EE applications face several vulnerabilities when it comes to storing and transferring data. Here are some common risks to be aware of:

Risk TypeImpactCommon Scenarios
Unencrypted Data TransitData interceptionUsing plain HTTP connections for sensitive data
Insecure StorageData breachStoring passwords or keys in plaintext files
Weak Transport LayerMan-in-the-middle attacksMisconfigured or missing SSL/TLS
Key Management IssuesUnauthorized accessHardcoding encryption keys in application code

Addressing these risks is crucial to ensure the safety of your application and user data.

Data Protection Methods

To secure data storage and transfer, focus on encryption and secure protocols:

  • Enforce HTTPS: Use the transport guarantee in your deployment descriptor to ensure data confidentiality [5].
  • Secrets Management: Utilize tools like Java KeyStore, HashiCorp Vault, or specialized MicroProfile Config Sources like SmallRye KeyStore Config Source, to manage encrypted secrets across different storage locations.
  • Add Security Headers: Use filters to strengthen HTTP responses. For example:
@WebFilter("/*")
public class SecurityHeadersFilter implements Filter {
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        httpResponse.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
        httpResponse.setHeader("X-Content-Type-Options", "nosniff");
        chain.doFilter(request, response);
    }
}

Using GlassFish server can further enhance security with its built-in security features and regular updates. Combined with proactive server maintenance and expert support from OmniFish, these practices help protect sensitive data across your Jakarta EE applications.

5. Preventing Injection Attacks

Types of Injection Attacks

Injection attacks are a major threat to Jakarta EE applications, exploiting non-validated user inputs to manipulate systems. Here’s an overview of the most common types:

Attack TypeDescriptionImpact
SQL InjectionAlters database queries with malicious SQL statementsData theft, corruption, or deletion
Command InjectionRuns unauthorized OS commandsSystem compromise
XML InjectionModifies XML processingData exposure, service disruption
LDAP InjectionAbuses dynamic LDAP queriesDirectory service compromise
NoSQL InjectionTargets non-relational databasesUnauthorized data access

For instance, during the Accellion FTA breach, attackers combined SQL injection with command execution to access encryption keys, compromise the system, and install a web shell [6].

Injection Prevention Steps

Protecting your application from these attacks requires careful implementation of key practices:

  • Use Parameterized Queries: Always rely on parameterized queries with PreparedStatement to bind inputs securely. Here’s an example:
// INCORRECT - vulnerable to injection
String query = "SELECT * FROM users WHERE username='" + username + "'";

// CORRECT - using parameterized query
String query = "SELECT * FROM users WHERE username = ?";
PreparedStatement stmt = connection.prepareStatement(query);
stmt.setString(1, username);
  • Validate Inputs: Enforce strict input validation to ensure only expected data is processed. For example:
@Entity
public class UserInput {
    @Pattern(regexp = "^[a-zA-Z0-9_]{3,20}$")
    private String username;

    @Size(min = 8, max = 50)
    private String comment;
}
  • Leverage Framework Security Features: Use built-in protections like the Jakarta Security API to control access and enforce security policies.
@Inject
private SecurityContext securityContext;

@GET
@Path("/secure")
public Response secureEndpoint() {
    if (!securityContext.isUserInRole("admin")) {
        return Response.status(Status.FORBIDDEN).build();
    }
    // Process secure operation
}

Safe Database Query Example

Here’s how you can securely construct dynamic queries using the JPA Criteria API:

@Stateless
public class SecureDataAccess {
    @PersistenceContext
    private EntityManager em;

    public List<User> findUsersByDepartment(String department) {
        // Using Criteria API for dynamic queries
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<User> query = cb.createQuery(User.class);
        Root<User> user = query.from(User.class);

        // Safe parameter handling
        Predicate departmentPredicate = cb.equal(
            user.get("department"), 
            cb.parameter(String.class, "dept")
        );

        query.where(departmentPredicate);

        TypedQuery<User> typedQuery = em.createQuery(query);
        typedQuery.setParameter("dept", department);

        return typedQuery.getResultList();
    }
}

“SQL Injection happens when a rogue attacker can manipulate the query building process so that he can execute a different SQL statement than what the application developer has originally intended.” – vladmihalcea [7]

Conclusion

Summary of Solutions

Ensuring strong Jakarta EE security requires a layered approach. The table below highlights key security measures and the tools to implement them effectively:

Security MeasureExample Implementation ToolKey Advantage
AuthenticationEclipse Epicyro (available in GlassFish)Provides standardized authentication
AuthorizationEclipse Exousia (available in GlassFish)Enables detailed access control
Dependency ManagementAzul Intelligence Cloud, Snyk Open SourceDelivers automated security updates and alerts about vulnerable dependencies
Input ValidationJakarta Security API (available in GlassFish)Protects against XSS and injection risks
Vulnerability DetectionContrast ADRHelps detect vulnerabilities early and protect from them

Applying these measures consistently is essential, as past breaches have shown the risks of neglecting security. Regular reviews further strengthen your system’s defenses.

Regular Security Checks

Security measures are only effective when maintained and updated. Here are key practices to ensure ongoing protection:

  • Dependency Management: Regularly review dependencies to eliminate unnecessary ones and update critical libraries and frameworks. This minimizes vulnerabilities and simplifies maintenance [8].
  • Security Testing: Use automated tools to scan for vulnerabilities in known databases, such as Contrast AST. This proactive approach helps identify and address risks before they are exploited.
  • Framework Integration: Take advantage of Jakarta Security‘s built-in features, which work seamlessly with Jakarta CDI. This ensures a consistent and reliable security setup across your application [9]. On top of that, check what other security features is offered by your app server, for example GlassFish.
  • Continuous Monitoring: Adopt a layered monitoring approach to quickly identify and address vulnerabilities through frequent assessments and updates [10].

Leave a Comment

Your email address will not be published. Required fields are marked *

Captcha loading...

Scroll to Top