Web Application and Client-Side Attacks Case Study

Web Application and Client-Side Attacks Case Study

Lab Objective

Learn to secure Java web applications using OWASP ESAPI (Enterprise Security API) by implementing input validation, output encoding, authentication, and security logging.

Learning Outcomes

By the end of this lab, you will be able to:

  • Validate input to reject unsafe user data
  • Encode output to prevent Cross-Site Scripting (XSS) attacks
  • Authenticate users securely with session management
  • Log security events without exposing sensitive information

Architecture Overview

This lab demonstrates a secure web application architecture using ESAPI components:

The application flow:

  1. User submits credentials → Input Validation
  2. Validated input → Authentication System
  3. Authentication result → Output Encoding
  4. All events → Security Logging

\newpage

Environment Setup

Install IntelliJ IDEA

  1. Download IntelliJ IDEA
  2. Install and launch the IDE

Create a New Maven Project

  1. Click File → New → Project

  1. Select the following options:
    • Language: Java
    • Build System: Maven
    • JDK: Version 11 or higher

If you don’t have a JDK installed, click “Download JDK” from the dropdown menu and select a version (e.g., Oracle JDK or Temurin).
  1. Click Create

Add Dependencies and Configuration Files

Configure Dependencies

  1. Open the pom.xml file in your project root
  2. Replace the contents of pom.xml with the following:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>esapi-security-lab</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!-- ESAPI Security Library -->
        <dependency>
            <groupId>org.owasp.esapi</groupId>
            <artifactId>esapi</artifactId>
            <version>2.7.0.0</version>
        </dependency>

        <!-- Servlet API -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <!-- Jetty Maven Plugin for running the application -->
            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.4.51.v20230217</version>
                <configuration>
                    <scanIntervalSeconds>10</scanIntervalSeconds>
                    <webApp>
                        <contextPath>/</contextPath>
                    </webApp>
                    <httpConnector>
                        <port>8080</port>
                    </httpConnector>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
  1. Click the Maven icon (usually in the top-right sidebar)

  1. Click the Reload button to download dependencies

This should download the needed dependencies, including ESAPI.

Create ESAPI Configuration Files

  1. Right-click on src/main/resources
  2. Select New → File
  3. Create a file named ESAPI.properties
  4. Add the following configuration:
Logger.LogEncodingRequired=false
Logger.UserInfo=true
Logger.ClientInfo=true
Logger.LogApplicationName=true
Logger.ApplicationName=ESAPITest
Logger.LogServerIP=true
Logger.LogFileName=ESAPI_logging_file
Logger.MaxLogFileSize=10000000

IntrusionDetector.Disable=false
IntrusionDetector.event.test.count=2
IntrusionDetector.event.test.interval=10
IntrusionDetector.event.test.actions=disable,log
IntrusionDetector.org.owasp.esapi.errors.IntrusionException.count=1
IntrusionDetector.org.owasp.esapi.errors.IntrusionException.interval=1
IntrusionDetector.org.owasp.esapi.errors.IntrusionException.actions=log,disable,logout
IntrusionDetector.org.owasp.esapi.errors.IntegrityException.count=10
IntrusionDetector.org.owasp.esapi.errors.IntegrityException.interval=5
IntrusionDetector.org.owasp.esapi.errors.IntegrityException.actions=log,disable,logout
IntrusionDetector.org.owasp.esapi.errors.AuthenticationHostException.count=2
IntrusionDetector.org.owasp.esapi.errors.AuthenticationHostException.interval=10
IntrusionDetector.org.owasp.esapi.errors.AuthenticationHostException.actions=log,logout

Validator.SafeString=^[a-zA-Z0-9]{1,50}$
Validator.Email=^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$

Setting up Jetty Server configuration

  1. Click on the Current File dropdown on the top-right corner of IntelliJ IDEA
  2. Select Edit Configurations…

  1. Click add new configuration and select Maven.
  2. Name it Run Jetty Server
  3. In the Command line field, enter: jetty:run

  1. Click Apply and then OK

Creating The Vulnerable Web Application

Vulnerable Login Servlet

  1. Create a new package: com.example.servlets
    • Right-click on src/main/java
    • Select New → Package
    • Name it com.example.servlets
  2. Inside the new package, create a class named VulnLoginServlet:
package com.example.servlets;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/vulnerableLogin")
public class VulnLoginServlet extends HttpServlet {

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

        response.setContentType("text/html");

        // Get user input WITHOUT validation
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        // Simulate simple authentication (accept any username/password)
        if (username != null && !username.isEmpty() && 
            password != null && !password.isEmpty()) {
            
            // Create session without proper validation
            request.getSession().setAttribute("username", username);

            response.sendRedirect("vulnerableInput.html");
            
            // No security logging
            System.out.println("User logged in: " + username);
        } else {
            response.getWriter().println("<h1>Login failed!</h1>");
            response.getWriter().println("<p>Please provide username and password.</p>");
        }
    }
}

Vulnerable Input servlet

  1. Inside the com.example.servlets package, create a class named VulnInputServlet:
package com.example.servlets;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/vulnerableInput")
public class VulnInputServlet extends HttpServlet {

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

        response.setContentType("text/html");

        // Weak session check
        String username = (String) request.getSession().getAttribute("username");
        if (username == null) {
            response.getWriter().println("<h1>Access Denied</h1>");
            response.getWriter().println("<p>You must be logged in to use this page.</p>");
            return;
        }

        // Get user input WITHOUT validation or encoding
        String userInput = request.getParameter("userInput");

        // VULNERABLE: Direct output without encoding - XSS vulnerability
        response.getWriter().println("<h1>Hello " + username + "</h1>");
        response.getWriter().println("<p>You entered: " + userInput + "</p>");
        
        // No input validation or security logging
    }
}

Create The HTML pages

Login Page

  1. Create a new directory: src/main/webapp
    • Right-click on src/main
    • Select New → Directory
    • Name it webapp
  2. Create vulnerableLogin.html in src/main/webapp:
<!DOCTYPE html>
<html>
<head>
    <title>Vulnerable Login</title>
</head>
<body>
<h2>Login Page</h2>
<p style="color: red;">Vulnerable version.</p>
<form action="vulnerableLogin" method="post">
    <label>Username: <input type="text" name="username"></label><br><br>
    <label>Password: <input type="password" name="password"></label><br><br>
    <button type="submit">Login</button>
</form>
</body>
</html>

Input Page

  1. Create vulnerableInput.html in src/main/webapp:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Input Page</title>
</head>
<body>
<h1>Enter Text</h1>
<p style="color: red;">Vulnerable version.</p>
<form action="vulnerableInput" method="post">
    <label for="userInput">Your Text:</label><br>
    <input type="text" id="userInput" name="userInput" required><br><br>
    <input type="submit" value="Submit">
</form>
</body>
</html>

Test The Vulnerable Application

Run the Jetty server by clicking the green Run button in the top-right corner.

Input Validation

  1. Open your web browser and navigate to: http://localhost:8080/vulnerableLogin.html
  2. Test various inputs on the username field:
    • Valid input: alice123
    • SQL Injection attempt: admin' OR '1'='1
    • XSS attempt: <script>alert('XSS')</script>
    • Empty fields
    • Special characters: user@#$%
  3. Observe that all inputs are accepted, demonstrating the lack of input validation.

If this username was passed to a database query, it could lead to SQL Injection.

We can also see that the XSS payload in the username gets executed.

Output Encoding

  1. After logging in, you should be redirected to the input page.
  2. Enter the following input to test XSS: <script>alert('XSS')</script>
  3. Observe that the script executes due to the lack of output encoding.

If we inspect element in the browser, we can see the script tag is directly included in the HTML.

Securing the Web Application

Implement Input Validation

Input validation is the first line of defense against injection attacks (SQL Injection, XSS, Command Injection).

Create the Validation Class

  1. Create a new package: com.example.security
    • Right-click on src/main/java
    • Select New → Package
    • Name it com.example.security
  2. Create a class named UserInputValidator
package com.example.security;

import org.owasp.esapi.ESAPI;
import org.owasp.esapi.Validator;
import org.owasp.esapi.errors.ValidationException;

public class UserInputValidator {
    
    public String validateUsername(String username) {
        Validator validator = ESAPI.validator();
        try {
            // "SafeString" is defined in validation.properties
            return validator.getValidInput("username", username, "SafeString", 50, false);
        } catch (ValidationException e) {
            System.out.println("Invalid input: " + e.getMessage());
            return null;
        }
    }
    
    public String validateEmail(String email) {
        Validator validator = ESAPI.validator();
        try {
            return validator.getValidInput("email", email, "Email", 100, false);
        } catch (ValidationException e) {
            System.out.println("Invalid email: " + e.getMessage());
            return null;
        }
    }
}

Implement Authentication

Proper authentication prevents unauthorized access and manages user sessions securely.

Create the Authentication Handler

Create a class named AuthenticationHandler:

package com.example.security;

import org.owasp.esapi.Authenticator;
import org.owasp.esapi.ESAPI;
import org.owasp.esapi.User;
import org.owasp.esapi.errors.AuthenticationException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class AuthenticationHandler {

    public boolean loginUser(HttpServletRequest request, HttpServletResponse response) {
        Authenticator auth = ESAPI.authenticator();
        ESAPI.httpUtilities().setCurrentHTTP(request, response);
        try {
            User user = auth.login(request, response);
            if (user != null && user.isLoggedIn()) {
                System.out.println("User logged in: " + user.getAccountName());
                return true;
            }
        } catch (AuthenticationException e) {
            System.out.println("Authentication failed: " + e.getMessage());
        }
        return true;
    }


    public void logoutUser(User user) {
        try {
            if (user != null) {
                user.logout();
                System.out.println("User logged out: " + user.getAccountName());
            }
        } catch (Exception e) {
            System.out.println("Logout failed: " + e.getMessage());
        }
    }
}

Implement Security Logging

Security logging helps detect attacks, audit user actions, and investigate security incidents.

Create the Logging Class

Create a class named SecurityLogger:

package com.example.security;

import org.owasp.esapi.ESAPI;
import org.owasp.esapi.Logger;

public class SecurityLogger {
    private static final Logger logger = ESAPI.getLogger(SecurityLogger.class);
    
    public void logSuccessfulLogin(String username) {
        logger.info(Logger.SECURITY_SUCCESS, "User logged in successfully: " + username);
    }
    
    public void logFailedLogin(String username) {
        logger.warning(Logger.SECURITY_FAILURE, "Failed login attempt for user: " + username);
    }
    
    public void logInputValidationFailure(String field, String value) {
        logger.warning(Logger.SECURITY_FAILURE, 
            "Input validation failed for field: " + field + " | Value: " + 
            ESAPI.encoder().encodeForHTML(value));
    }
    
    public void logSuspiciousActivity(String username, String activity) {
        logger.error(Logger.SECURITY_AUDIT, 
            "Suspicious activity detected | User: " + username + " | Activity: " + activity);
    }
}

Integrate Components into the Servlet

Now let’s integrate all components into a working servlet.

Create The Secure Login Servlet

Inside the com.example.servlets package, create a class named LoginServlet:

package com.example.servlets;

import com.example.security.UserInputValidator;
import com.example.security.AuthenticationHandler;
import com.example.security.SecurityLogger;
import org.owasp.esapi.ESAPI;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

@WebServlet("/login")
public class LoginServlet extends HttpServlet {

    private final UserInputValidator validator = new UserInputValidator();
    private final AuthenticationHandler authHandler = new AuthenticationHandler();
    private final SecurityLogger securityLogger = new SecurityLogger();


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

        response.setContentType("text/html");

        // Step 1: Get user input
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        // Step 2: Validate input
        String safeUsername = validator.validateUsername(username);
        if (safeUsername == null) {
            response.getWriter().println("Unsafe input detected!");
            securityLogger.logInputValidationFailure("username", username);
            return;
        }

        // Step 3: Authenticate user
        if (authHandler.loginUser(request, response)) {
            // Step 4: Encode output before sending to client (prevents XSS)
            String safeOutput = ESAPI.encoder().encodeForHTML("Welcome " + safeUsername + "!");
            response.getWriter().println("<h1>" + safeOutput + "</h1>");

            response.sendRedirect("input.html");

            // Step 5: Log successful login
            securityLogger.logSuccessfulLogin(safeUsername);

            // Create session
            request.getSession().setAttribute("username", safeUsername);

        } else {
            response.getWriter().println("<h1>Login failed!</h1>");
            securityLogger.logFailedLogin(safeUsername);
        }
    }
}

Create The Secure Input Servlet

Inside the com.example.servlets package, create a class named InputServlet:

package com.example.servlets;

import org.owasp.esapi.ESAPI;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/input")
public class InputServlet extends HttpServlet {

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

        response.setContentType("text/html");

        // Check if user is logged in
        String username = (String) request.getSession().getAttribute("username");
        if (username == null) {
            response.getWriter().println("<h1>Access Denied</h1><p>You must be logged in to use this page.</p>");
            return;
        }

        // Get and encode user input
        String userInput = request.getParameter("userInput");
        String safeOutput = ESAPI.encoder().encodeForHTML(userInput);

        response.getWriter().println("<h1>Hello " + ESAPI.encoder().encodeForHTML(username) + "</h1>");
        response.getWriter().println("<p>You entered: " + safeOutput + "</p>");
    }
}

Create The Secure HTML Pages

Login Page

Create login.html in src/main/webapp:

<!DOCTYPE html>
<html>
<head>
    <title>Secure Login</title>
</head>
<body>
<h2>Login Page</h2>
<p style="color: green;">ESAPI secured version.</p>
<form action="login" method="post">
    <label>Username: <input type="text" name="username"></label><br><br>
    <label>Password: <input type="password" name="password"></label><br><br>
    <button type="submit">Login</button>
</form>
</body>
</html>

Input Page

Create input.html in src/main/webapp:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Input Page</title>
</head>
<body>
<h1>Enter Text</h1>
<p style="color: green;">ESAPI secured version.</p>
<form action="/input" method="post">
    <label for="userInput">Your Text:</label><br>
    <input type="text" id="userInput" name="userInput" required><br><br>
    <input type="submit" value="Submit">
</form>
</body>
</html>

At the end your project structure should look like this:

ESAPITest/
├── pom.xml
├── src
│   ├── main
│   │   ├── java
│   │   │   └── com
│   │   │       └── example
│   │   │           ├── security
│   │   │           │   ├── AuthenticationHandler.java
│   │   │           │   ├── SecurityLogger.java
│   │   │           │   └── UserInputValidator.java
│   │   │           └── servlets
│   │   │               ├── InputServlet.java
│   │   │               ├── LoginServlet.java
│   │   │               ├── VulnInputServlet.java
│   │   │               └── VulnLoginServlet.java
│   │   └── resources
│   │       └── ESAPI.properties
│   └── webapp
│       ├── input.html
│       ├── login.html
│       ├── vulnerableInput.html
│       └── vulnerableLogin.html

Testing The Secure Application

Run the Jetty server by clicking the green Run button in the top-right corner.

Input Validation

  1. Open your web browser and navigate to: http://localhost:8080/login.html
  2. Test various inputs on the username field:
    • Valid input: alice123
    • SQL Injection attempt: admin' OR '1'='1
    • XSS attempt: <script>alert('XSS')</script>
    • Empty fields
    • Special characters: user@#$%
  3. Observe that unsafe inputs are rejected, demonstrating effective input validation.

Using the same SQL Injection attempt now gets rejected.

Output Encoding

  1. After logging in, you should be redirected to the input page.
  2. Enter the following input to test XSS: <script>alert('XSS')</script
  3. Observe that the script does not execute and shows up as plain text, demonstrating effective output encoding.

The XSS payload is now safely encoded and does not execute.

Conclusion

In this lab, you have successfully transformed a vulnerable web application into a secure one using OWASP ESAPI. You have implemented:

  • Input validation to reject unsafe user data
  • Output encoding to prevent XSS attacks
  • Secure user authentication with session management
  • Security logging to monitor and audit security events

By following these best practices you can build secure web applications.