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:
- User submits credentials → Input Validation
- Validated input → Authentication System
- Authentication result → Output Encoding
- All events → Security Logging
\newpage
Environment Setup
Install IntelliJ IDEA
- Download IntelliJ IDEA
- Install and launch the IDE
Create a New Maven Project
- Click File → New → Project

- Select the following options:
- Language: Java
- Build System: Maven
- JDK: Version 11 or higher

- Click Create
Add Dependencies and Configuration Files
Configure Dependencies
- Open the
pom.xmlfile in your project root - Replace the contents of
pom.xmlwith 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>- Click the Maven icon (usually in the top-right sidebar)
![]()
- Click the Reload button to download dependencies
This should download the needed dependencies, including ESAPI.
Create ESAPI Configuration Files
- Right-click on
src/main/resources - Select New → File
- Create a file named
ESAPI.properties - 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
- Click on the
Current Filedropdown on the top-right corner of IntelliJ IDEA - Select Edit Configurations…

- Click add new configuration and select Maven.
- Name it
Run Jetty Server - In the
Command linefield, enter:jetty:run

- Click Apply and then OK
Creating The Vulnerable Web Application
Vulnerable Login Servlet
- Create a new package:
com.example.servlets- Right-click on
src/main/java - Select New → Package
- Name it
com.example.servlets
- Right-click on
- 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
- Inside the
com.example.servletspackage, create a class namedVulnInputServlet:
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
- Create a new directory:
src/main/webapp- Right-click on
src/main - Select New → Directory
- Name it
webapp
- Right-click on
- Create
vulnerableLogin.htmlinsrc/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
- Create
vulnerableInput.htmlinsrc/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
- Open your web browser and navigate to: http://localhost:8080/vulnerableLogin.html
- 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@#$%
- Valid input:
- 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
- After logging in, you should be redirected to the input page.
- Enter the following input to test XSS:
<script>alert('XSS')</script> - 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
- Create a new package:
com.example.security- Right-click on
src/main/java - Select New → Package
- Name it
com.example.security
- Right-click on
- 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.htmlTesting The Secure Application
Run the Jetty server by clicking the green Run button in the top-right corner.
Input Validation
- Open your web browser and navigate to: http://localhost:8080/login.html
- 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@#$%
- Valid input:
- Observe that unsafe inputs are rejected, demonstrating effective input validation.

Using the same SQL Injection attempt now gets rejected.
Output Encoding
- After logging in, you should be redirected to the input page.
- Enter the following input to test XSS:
<script>alert('XSS')</script - 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.