Defending Against Threats!

Himani Perera
10 min readOct 8, 2023

--

Securing Your Web App by Defeating OWASP Top 10 Vulnerabilities

Hi guys, Welcome back! to the second installment of my article series. In our previous article ‘Building Trust with OpenID Connect Protocols’, we explored how to verify the identity of end-users and implement basic user profile functionality using Asgardeo OpenID Connect protocols in the context of our Auto Care Vehicle Services web application (you can access the source code here).

In this next chapter of our journey, we will take a deep dive into fortifying our web application against some of the most common and critical security threats outlined in the OWASP (Open Web Application Security Project) Top 10 list. The web landscape is constantly evolving, and as developers, it’s our responsibility to stay one step ahead in the ongoing battle against vulnerabilities and malicious actors.

In this article, we will equip you with the knowledge and tools needed to proactively secure your application. We’ll address key concepts and practical strategies to defend against these vulnerabilities, ensuring that our Auto Care Vehicle Services application remains resilient and our users’ data stays protected.

So, fasten your seatbelts, as we embark on this crucial journey to bolster the security of your web app. Together, we’ll navigate the challenging terrain of the OWASP Top 10 and emerge with a stronger, more secure application. Let’s get started! 😎

The numbered waypoints of my exploration:

  1. Understanding the OWASP Top 10
  2. Securing Against Broken Access Control
  3. Unpacking Injection Vulnerabilities
  4. Defending Against SQL Injection
  5. Shielding Against XSS Attacks
  6. Learning Outcomes

1️⃣ Understanding the OWASP Top 10

OWASP, which stands for the Open Web Application Security Project, is a global nonprofit organization committed to enhancing the security of web applications. One of the OWASP’s well-known initiatives is the ‘OWASP Top 10 which is a regularly updated report that highlights the most critical security concerns related to web application security. This report is collaboratively developed by a team of security experts from various parts of the world. OWASP categorizes the Top 10 as an “awareness document” and strongly recommends that all companies integrate its insights into their processes to effectively minimize and mitigate security risks.

Below are the top 10 security risks reported in the OWASP Top 10 2021 report.

OWASP Top 10

Throughout this article, I will illustrate the techniques employed to address specific vulnerabilities from the OWASP Top 10. It’s worth noting that our Auto Care Vehicle Services web application may not exhibit all ten of these vulnerabilities. Nonetheless, I will demonstrate how to effectively test for and mitigate some major vulnerabilities during the development process.

2️⃣ Securing Against Broken Access Control

Poor implementation of access control mechanisms leads to flawed access control, which can be easily exploited. This condition is referred to as “broken access control.” When access control is broken, unauthorized individuals gain the ability to access restricted content, and execute unauthorized actions, and in some cases, attackers can even delete content or assume control over site administration.

Broken Access Control

Now let’s see how to protect our web application from Broken Access Control.

Using an OpenID Connect for user authentication is an effective way to prevent broken access control on our web application. OpenID Connect provides a secure and standardized method for verifying the identity of users, ensuring that only authorized individuals can access the home page and other pages of our web app. Here’s how I’ve achieved it:

When users try to access any page (except the index.jsp) in our website, or a protected resource or try to perform a privileged action, they will be redirected to the OpenID Connect IdP for authentication. The IdP will authenticate the user and issue an ID token and an access token.

When a user makes a request to access any page (except the index.jsp) or a protected resource on our web application, ensure that the user includes an access token in the request. If not, they will be redirected to the OpenID Connect IdP for authentication. Then the IdP will authenticate the user and issue an ID token and an access token. We can use Asgardeo’s token introspection endpoint to validate this access token sent by the user. Then the introspection endpoint will respond with information about the token’s validity and associated claims. we can inspect the response to determine whether the user has the necessary permissions to access the requested resource.

String introUrl = "https://api.asgardeo.io/t/<organization_name>/oauth2/introspect";

Based on the introspection response, your resource server should make access control decisions. Ensure that you validate the user’s permissions and whether they are authorized to access the requested resource. If the introspection response indicates that the token is invalid or the user is not authorized, deny access to the resource and return an appropriate error response (e.g., HTTP 401 Unauthorized or HTTP 403 Forbidden).

By implementing token validation through Asgardeo’s introspection endpoint, we can enhance the security of our Auto Care Vehicle Services web application by preventing broken access control and ensuring that only authorized users can access protected resources.

3️⃣ Unpacking Injection Vulnerabilities

Injection vulnerabilities occur when an attacker supplies untrusted data to a program, which is then processed as part of a command or query by a code interpreter. This malicious input can lead to unintended commands being executed, altering the normal behavior of the program. Injection attacks typically happen when an application accepts unvalidated input and directly passes it to a database or server, allowing the input to execute.

While SQL injection is a well-known type of injection vulnerability, others like NoSQL, OS, and LDAP injections also exist. What makes injection vulnerabilities so perilous is their broad attack surface; nearly any data can serve as a vector for an attack. The consequences of such vulnerabilities are severe and encompass data loss, data theft, denial of service, compromised data integrity, and even complete system takeover.

Let’s explore how we can take proactive steps to mitigate injection vulnerabilities within our web application, starting with a focus on SQL injection.

4️⃣ Defending Against SQL Injection

SQL injection 💉 is one of the most common types of injection that occurs when an attacker is able to manipulate or inject malicious SQL (Structured Query Language) code into a database query. This can happen when an application does not properly validate and sanitize user inputs before incorporating them into SQL queries.

In our web application’s VehicleServiceDao.java class, I've implemented essential techniques to safeguard against SQL injection. This class serves as the hub for all SQL statements in our application, making it a critical area for preventing this type of vulnerability. Let’s see the measures I've taken designed to fortify our application's security against SQL injection.

Prepared Statements with Parametrized Queries:

The class uses prepared statements for SQL queries that involve user input. Prepared statements ensure that user input is treated as data and not executable SQL code. This is a fundamental technique for preventing SQL injection.

private static final String INSERT_VEHICLESERVICE_SQL = "INSERT INTO vehicle_service" + "  (date, time, location, vehicle_no, mileage, message, username) VALUES "
+ " (?, ?, ?, ?, ?, ?, ?);";

The INSERT_VEHICLESERVICE_SQL constant represents a prepared statement for inserting a new vehicle service record into the database. It uses parameter placeholders (?) to safely insert user-provided data into the SQL query.

PreparedStatement preparedStatement = connection.prepareStatement(INSERT_VEHICLESERVICE_SQL);
preparedStatement.setDate(1, sqlDate);
preparedStatement.setTime(2, Time.valueOf(vehicleService.getTime()));
preparedStatement.setString(3, vehicleService.getLocation());
preparedStatement.setString(4, vehicleService.getVehicle_no());
preparedStatement.setInt(5, vehicleService.getMileage());
preparedStatement.setString(6, vehicleService.getMessage());
preparedStatement.setString(7, vehicleService.getUserName());

The above code sets values for the parameters using safe parameter-setting methods, ensuring that user input is treated as data rather than executable SQL code. Parameterized Queries ensure that user inputs are treated as data, not executable SQL code. This practice automatically escapes and protects the inputs.

Moreover, the SELECT_ALL_VEHICLESERVICE_BY_EMAIL constant also represents a prepared statement for selecting vehicle service records based on a username parameter. It uses a parameter placeholder (?) to safely include the user-provided username in the SQL query.

private static final String SELECT_ALL_VEHICLESERVICE_BY_EMAIL = "SELECT * FROM vehicle_service WHERE username = ?";

The code sets the value of the parameter using the setString method, ensuring that the username is properly sanitized and preventing SQL injection.

PreparedStatement preparedStatement = connection.prepareStatement(SELECT_ALL_VEHICLESERVICE_BY_EMAIL);
preparedStatement.setString(1, username);

Similarly, upon reviewing the source code, you’ll notice that I’ve extended these security measures to the delete statement as well. In essence, we’ve applied the same protective techniques consistently throughout our codebase to ensure that all interactions with the database are safeguarded against SQL injection vulnerabilities.

Sanitization:

Sanitizing the user inputs to remove or escape any potentially harmful characters has also been used to prevent SQL injection. Here, we can also use appropriate sanitization methods or libraries for each input type.

private void insertVehicleService(HttpServletRequest request, HttpServletResponse response)throws SQLException, IOException 
{
// sanitizing the user inputs to escape any potentially harmful characters

String date = request.getParameter("date").replaceAll("'", "''");
String time = request.getParameter("time").replaceAll("'", "''");
String location = request.getParameter("location").replaceAll("'", "''");
String vehicle_no = request.getParameter("vehicle_no").replaceAll("'", "''");
int mileage = Integer.parseInt(request.getParameter("mileage"));
String message = request.getParameter("message").replaceAll("'", "''");
String username = request.getParameter("username").replaceAll("'", "''");

VehicleService newVehicleService = new VehicleService(date, time, location, vehicle_no, mileage, message, username);
vehicleServiceDao.insertVehicleService(newVehicleService);

response.sendRedirect("list");
}

The provided code is an example of how I have sanitized user inputs in our VehicleServiceServlet.java class before they were inserted into the database. Sanitizing user inputs is a critical security practice to prevent SQL injection and other potential security vulnerabilities.

5️⃣ Shielding Against XSS Attacks

Cross-Site Scripting (XSS) attacks represent a form of injection where harmful scripts are inserted into typically trustworthy websites. Such attacks transpire when a malevolent actor exploits a web application to transmit malicious code, typically in the form of a client-side script, to another unsuspecting user. Vulnerabilities that enable the success of XSS attacks are prevalent and manifest whenever a web application incorporates user input into its output without validating or encoding it.

let’s evaluate our Auto Care Vehicle Services web app source code against XSS.

Input Validation:

To neutralize user inputs and avoid Cross-Site Scripting (XSS) vulnerabilities, it’s important to sanitize validate the data properly.

Instead of manually replacing characters, we can use a library or framework designed for this purpose. In our web app, I have used the Apache Commons Text library to escape HTML characters. For that, you need to import the below library that is included in the commons-text-1.10.0.jar’ file.

import org.apache.commons.text.StringEscapeUtils;

The below-provided code is an improved version of our original insertVehicleService method in our VehicleServiceServlet.java class. That demonstrates how to avoid Cross-Site Scripting (XSS) vulnerabilities by sanitizing and neutralizing user inputs using the escapeHtml4() method from Apache Commons Text.

//insert vehicle service
private void insertVehicleService(HttpServletRequest request, HttpServletResponse response)throws SQLException, IOException
{

// sanitizing the user inputs to escape any potentially harmful characters
//neutralizing the user inputs using escapeHtml4() method
String date = StringEscapeUtils.escapeHtml4(request.getParameter("date").replaceAll("'", "''"));

String time = StringEscapeUtils.escapeHtml4(request.getParameter("time").replaceAll("'", "''"));

String location = StringEscapeUtils.escapeHtml4(request.getParameter("location").replaceAll("'", "''"));

String vehicle_no = StringEscapeUtils.escapeHtml4(request.getParameter("vehicle_no").replaceAll("'", "''"));

int mileage = Integer.parseInt(request.getParameter("mileage"));

String message = StringEscapeUtils.escapeHtml4(request.getParameter("message").replaceAll("'", "''"));

String username = StringEscapeUtils.escapeHtml4(request.getParameter("username").replaceAll("'", "''"));

VehicleService newVehicleService = new VehicleService(date, time, location, vehicle_no, mileage, message, username);

vehicleServiceDao.insertVehicleService(newVehicleService);

response.sendRedirect("list");

}

By applying escapeHtml4() to sanitize and neutralize user inputs, the code ensures that any potentially malicious HTML or JavaScript code is transformed into harmless text entities. This prevents XSS attacks when the sanitized data is later displayed in our web application, making our application more secure against this type of vulnerability.

(You can apply the method to each user input field before storing them in the database.)

Output Encoding:

I have encoded all user-generated content before displaying it in our application. Use HTML encoding to convert special characters like <, >, and & into their respective HTML entities.
To avoid Cross-Site Scripting (XSS) vulnerabilities in our JSP code, we can use output encoding to safely display user-generated content. I’ve achieved this by using the <c:out> tag along with the escapeXml attribute set to true. Here's how I’ve modified the code:

<tbody>

<c:forEach var="vehicleService" items="${listVehicleSerivice}">

<tr>
<!-- use output encoding to safely display user-generated content -->
<td><c:out value="${vehicleService.booking_id}" escapeXml="true"/></td>
<td><c:out value="${vehicleService.date}" escapeXml="true"/></td>
<td><c:out value="${vehicleService.time}" escapeXml="true"/></td>
<td><c:out value="${vehicleService.location}" escapeXml="true"/></td>
<td><c:out value="${vehicleService.vehicle_no}" escapeXml="true"/></td>
<td><c:out value="${vehicleService.mileage}" escapeXml="true"/></td>
<td><c:out value="${vehicleService.message}" escapeXml="true"/></td>
<td><a href="delete?booking_id=<c:out value='${vehicleService.booking_id}' />">Delete</a></td>
</tr>
</c:forEach>

</tbody>

By adding the escapeXml="true" attribute to each <c:out> tag, we can ensure that any user-generated content within these tags is properly escaped and displayed as plain text. This prevents any potentially malicious scripts or HTML tags from being executed in the browser, effectively protecting your web application from XSS attacks.

Bravo! 🙌 In this comprehensive journey through the intricacies of web application security, I’ve covered a multitude of techniques to safeguard our beloved Auto Care Vehicle Services web application. From defending against Broken Access Control to mitigating Injection Vulnerabilities and tackling Cross-Site Scripting (XSS) threats. I trust that you’ve gained a robust understanding of how to effectively mitigate these vulnerabilities.

6️⃣ Learning Outcomes

As we wrap up this insightful blog, let’s reflect on the valuable learning outcomes:

  1. Understanding Vulnerabilities: We’ve gained a profound understanding of common web application vulnerabilities, from Broken Access Control to SQL Injection and XSS threats.
  2. Proactive Defense: We’ve learned proactive defense strategies, such as implementing proper access controls, validating and sanitizing user inputs, and encoding output to thwart potential attacks.
  3. Security Awareness: We’ve cultivated a heightened sense of security awareness, realizing the importance of constant vigilance in safeguarding our digital assets.
  4. Ongoing Improvement: We’ve embraced the notion that web application security is an ongoing process, and our commitment to continuous improvement will be our strongest defense.

With these invaluable lessons, we’re better equipped to navigate the complex landscape of web application security and ensure a safer online experience for all. Let’s carry these insights forward, fortify our applications, and stay one step ahead of the ever-evolving threat landscape.

So, keep coding securely, keep testing rigorously, and keep your users’ data and trust safe. Cheers to your web application’s bright and secure future! 🛡️🌐

Safe coding, everyone! 🚀🔒

References

--

--

Himani Perera

Final Year Software Engineering Undergraduate at University of Kelaniya, Sri Lanka