Business information leak - DB - Java

Business information leak - DB - Java

Need

Protection of sensitive business information stored in the database

Context

  • Usage of Java for building cross-platform applications
  • Usage of javax.servlet for building Java web applications with Servlet technology
  • Usage of java.io for input and output operations in Java
  • Usage of java.sql for connecting and interacting with databases in Java applications

Description

Non compliant code

        import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.sql.*;

public class VulnerableServlet extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        
        try {
            Class.forName("com.mysql.jdbc.Driver");
            Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb","root","password");
            Statement stmt = con.createStatement();
            ResultSet rs = stmt.executeQuery("SELECT * FROM Transactions");
            
            while(rs.next()) {
                out.println("User: " + rs.getString(1) + "
"); out.println("Document Number: " + rs.getString(2) + "
"); out.println("Full Name: " + rs.getString(3) + "
"); out.println("Wallet ID: " + rs.getString(4) + "
"); out.println("OS Name: " + rs.getString(5) + "
"); out.println("Transaction Code: " + rs.getString(6) + "
"); out.println("Endpoint: " + rs.getString(7) + "
"); out.println("Credit Card: " + rs.getString(8) + "
"); out.println("Available Balance: " + rs.getString(9) + "
"); } con.close(); } catch(Exception e) { out.println(e); } } }

The above code is a Servlet that connects to a MySQL database and retrieves all the transactions. It then prints all the information about each transaction, including sensitive business information, to the response object, which is sent to the client.

The problem lies in the fact that no authentication or authorization checks are made before the information is retrieved and sent to the client. This means that anyone who can make a request to this Servlet can get all the business information.

Additionally, the database connection details, including the username and password, are hard-coded into the source code. This is a bad practice as it exposes these sensitive details to anyone who has access to the source code.

Finally, the code does not use prepared statements for the SQL query, which makes it vulnerable to SQL Injection attacks. An attacker could potentially manipulate the SQL query to gain unauthorized access to other data in the database.

Steps

  • Remove the sensitive information from the source code.
  • Store the sensitive information in a secure location, such as a configuration file or environment variables.
  • Implement proper access controls to restrict access to the sensitive information.
  • Use parameterized queries or prepared statements to prevent SQL injection attacks.
  • Implement input validation and sanitization to prevent malicious input.
  • Encrypt the sensitive information before storing it in the database.
  • Implement secure communication protocols, such as HTTPS, to protect the transmission of sensitive information.
  • Regularly update and patch the software components used in the application to address any known vulnerabilities.
  • Implement logging and monitoring mechanisms to detect and respond to any unauthorized access or suspicious activities.

Compliant code

        import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.sql.*;
import javax.sql.DataSource;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class SecureServlet extends HttpServlet {
    private DataSource dataSource;

    @Override
    public void init() throws ServletException {
        try {
            InitialContext initialContext = new InitialContext();
            dataSource = (DataSource) initialContext.lookup("java:comp/env/jdbc/mydb");
        } catch (NamingException e) {
            throw new ServletException("Cannot retrieve datasource", e);
        }
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();

        try (Connection con = dataSource.getConnection()) {
            PreparedStatement stmt = con.prepareStatement("SELECT * FROM Transactions WHERE user_id = ?");
            stmt.setString(1, request.getUserPrincipal().getName());

            ResultSet rs = stmt.executeQuery();

            while(rs.next()) {
                out.println("User: " + rs.getString(1) + "
"); out.println("Document Number: " + rs.getString(2) + "
"); out.println("Full Name: " + rs.getString(3) + "
"); out.println("Wallet ID: " + rs.getString(4) + "
"); out.println("OS Name: " + rs.getString(5) + "
"); out.println("Transaction Code: " + rs.getString(6) + "
"); out.println("Endpoint: " + rs.getString(7) + "
"); out.println("Credit Card: " + rs.getString(8) + "
"); out.println("Available Balance: " + rs.getString(9) + "
"); } } catch(Exception e) { out.println(e); } } }

The above code is a revised version of the original vulnerable servlet. The changes made are as follows:

- The database connection details are no longer hard-coded in the servlet. Instead, the servlet retrieves the DataSource from the JNDI environment. This prevents sensitive information such as the database URL, username, and password from being exposed in the source code.

- The SQL query is now parameterized to prevent SQL injection attacks. The PreparedStatement is used instead of Statement, and the user ID is set as a parameter in the query.

- The servlet now only retrieves the transactions for the authenticated user. This is done by calling request.getUserPrincipal().getName() to get the name of the authenticated user, and using this as the parameter in the SQL query. This prevents unauthorized access to other users' transactions.

- The sensitive information is still displayed in the response. However, this is just for demonstration purposes. In a real application, this information should be encrypted or hashed before being stored in the database, and should not be displayed in plain text in the response.

- The connection is now managed within a try-with-resources block, which ensures that the connection is always closed, even if an exception occurs. This prevents potential connection leaks.

- The servlet now implements the init method to retrieve the DataSource. This is done only once when the servlet is initialized, instead of every time the doGet method is called. This improves the performance of the servlet.

- The servlet now catches NamingException in the init method. This is a checked exception that can be thrown when looking up the DataSource in the JNDI environment. By catching this exception, the servlet can provide a more meaningful error message if the DataSource cannot be retrieved.

References