Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 143 additions & 0 deletions src/main/java/demo/security/servlet/ContactFeedbackServlet.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package demo.security.servlet;

import demo.security.util.ContactFeedbackUtil;
import demo.security.util.ContactFeedbackException;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

@WebServlet("/contact-feedback")
public class ContactFeedbackServlet extends HttpServlet {

// Constants for string literals
private static final String FIELD_NAME = "name";
private static final String FIELD_EMAIL = "email";
private static final String FIELD_FEEDBACK = "feedback";
private static final String FIELD_CATEGORY = "category";
private static final String FIELD_ID = "id";
private static final String HTML_START = "<html><body>";
private static final String HTML_END = "</body></html>";

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String name = request.getParameter(FIELD_NAME);
String email = request.getParameter(FIELD_EMAIL);
String feedback = request.getParameter(FIELD_FEEDBACK);
String category = request.getParameter(FIELD_CATEGORY);

ContactFeedbackUtil util = createUtil();

Check notice

Code scanning / SonarQube

Exceptions should not be thrown from servlet methods Low

Handle the following exception that could be thrown by "createUtil": ServletException. See more on SonarQube

// Store feedback with SQL injection vulnerability
String feedbackId = storeFeedback(util, name, email, feedback, category);

Check notice

Code scanning / SonarQube

Exceptions should not be thrown from servlet methods Low

Handle the following exception that could be thrown by "storeFeedback": ServletException. See more on SonarQube

// Retrieve and display feedback
List<Map<String, String>> feedbackList = getFeedbackByEmail(util, email);

Check notice

Code scanning / SonarQube

Exceptions should not be thrown from servlet methods Low

Handle the following exception that could be thrown by "getFeedbackByEmail": ServletException. See more on SonarQube

renderFeedbackSubmissionResponse(response, feedbackId, feedbackList);

Check notice

Code scanning / SonarQube

Exceptions should not be thrown from servlet methods Low

Handle the following exception that could be thrown by "renderFeedbackSubmissionResponse": IOException. See more on SonarQube
}

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String searchEmail = request.getParameter(FIELD_EMAIL);
String searchCategory = request.getParameter(FIELD_CATEGORY);

ContactFeedbackUtil util = createUtil();

Check notice

Code scanning / SonarQube

Exceptions should not be thrown from servlet methods Low

Handle the following exception that could be thrown by "createUtil": ServletException. See more on SonarQube
List<Map<String, String>> feedbackList = getFeedbackList(util, searchEmail, searchCategory);

Check notice

Code scanning / SonarQube

Exceptions should not be thrown from servlet methods Low

Handle the following exception that could be thrown by "getFeedbackList": ServletException. See more on SonarQube

renderFeedbackSearchResponse(response, feedbackList);

Check notice

Code scanning / SonarQube

Exceptions should not be thrown from servlet methods Low

Handle the following exception that could be thrown by "renderFeedbackSearchResponse": IOException. See more on SonarQube
}

private ContactFeedbackUtil createUtil() throws ServletException {
try {
return new ContactFeedbackUtil();
} catch (SQLException e) {
throw new ServletException("Database connection failed", e);
}
}

private String storeFeedback(ContactFeedbackUtil util, String name, String email, String feedback, String category) throws ServletException {
try {
return util.storeFeedback(name, email, feedback, category);
} catch (ContactFeedbackException e) {
throw new ServletException("Failed to store feedback", e);
}
}

private List<Map<String, String>> getFeedbackByEmail(ContactFeedbackUtil util, String email) throws ServletException {
try {
return util.getFeedbackByEmail(email);
} catch (ContactFeedbackException e) {
throw new ServletException("Failed to retrieve feedback", e);
}
}

private List<Map<String, String>> getFeedbackList(ContactFeedbackUtil util, String searchEmail, String searchCategory) throws ServletException {
try {
if (searchEmail != null && !searchEmail.isEmpty()) {
// SQL injection vulnerability in search
return util.getFeedbackByEmail(searchEmail);
} else if (searchCategory != null && !searchCategory.isEmpty()) {
return util.getFeedbackByCategory(searchCategory);
} else {
return util.getAllFeedback();
}
} catch (ContactFeedbackException e) {
throw new ServletException("Failed to search feedback", e);
}
}

private void renderFeedbackSubmissionResponse(HttpServletResponse response, String feedbackId, List<Map<String, String>> feedbackList) throws IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();

out.println(HTML_START);
out.println("<h2>Thank you for your feedback!</h2>");
out.println("<p>Your feedback ID: " + feedbackId + "</p>");
out.println("<h3>Your previous feedback:</h3>");

renderFeedbackItems(out, feedbackList);

out.println(HTML_END);
out.close();
}

private void renderFeedbackSearchResponse(HttpServletResponse response, List<Map<String, String>> feedbackList) throws IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();

out.println(HTML_START);
out.println("<h2>Feedback Results</h2>");

for (Map<String, String> fb : feedbackList) {
// XSS vulnerability
out.println("<div>");
out.println("<p><b>ID:</b> " + fb.get(FIELD_ID) + "</p>");
out.println("<p><b>Name:</b> " + fb.get(FIELD_NAME) + "</p>");
out.println("<p><b>Email:</b> " + fb.get(FIELD_EMAIL) + "</p>");
out.println("<p><b>Category:</b> " + fb.get(FIELD_CATEGORY) + "</p>");
out.println("<p><b>Feedback:</b> " + fb.get(FIELD_FEEDBACK) + "</p>");
out.println("</div><hr>");
}

out.println(HTML_END);
out.close();
}

private void renderFeedbackItems(PrintWriter out, List<Map<String, String>> feedbackList) {
for (Map<String, String> fb : feedbackList) {
// XSS vulnerability - directly outputting user input
out.println("<div>");
out.println("<p><b>Name:</b> " + fb.get(FIELD_NAME) + "</p>");
out.println("<p><b>Email:</b> " + fb.get(FIELD_EMAIL) + "</p>");
out.println("<p><b>Category:</b> " + fb.get(FIELD_CATEGORY) + "</p>");
out.println("<p><b>Feedback:</b> " + fb.get(FIELD_FEEDBACK) + "</p>");
out.println("</div><hr>");
}
}
}
13 changes: 13 additions & 0 deletions src/main/java/demo/security/util/ContactFeedbackException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package demo.security.util;

public class ContactFeedbackException extends Exception {

public ContactFeedbackException(String message) {
super(message);
}

public ContactFeedbackException(String message, Throwable cause) {
super(message, cause);
}
}

143 changes: 143 additions & 0 deletions src/main/java/demo/security/util/ContactFeedbackUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package demo.security.util;

import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

public class ContactFeedbackUtil {

// Constants for string literals
private static final String FIELD_ID = "id";
private static final String FIELD_NAME = "name";
private static final String FIELD_EMAIL = "email";
private static final String FIELD_FEEDBACK = "feedback";
private static final String FIELD_CATEGORY = "category";

private Connection connection;
private final Random random;
private final String feedbackBasePath;

public ContactFeedbackUtil() throws SQLException {
connection = DriverManager.getConnection(
"myJDBCUrl", "myJDBCUser", "myJDBCPass");

Check failure

Code scanning / SonarQube

Credentials should not be hard-coded Critical

Revoke and change this password, as it is compromised. See more on SonarQube
this.random = new Random();
this.feedbackBasePath = System.getProperty("feedback.base.path", "/var/feedback/");
}

// SQL Injection vulnerability - string concatenation
public String storeFeedback(String name, String email, String feedback, String category) throws ContactFeedbackException {
String feedbackId = generateFeedbackId();

// SQL injection through string concatenation
String query = "INSERT INTO feedback (id, name, email, feedback, category) VALUES ('"
+ feedbackId + "', '"
+ name + "', '"
+ email + "', '"
+ feedback + "', '"
+ category + "')";

try (Statement statement = connection.createStatement()) {
statement.executeUpdate(query);

Check failure

Code scanning / SonarQube

Database queries should not be vulnerable to injection attacks Critical

Change this code to not construct SQL queries directly from user-controlled data. See more on SonarQube
} catch (SQLException e) {
throw new ContactFeedbackException("Failed to store feedback", e);
}

return feedbackId;
}

// SQL Injection vulnerability - string concatenation in WHERE clause
public List<Map<String, String>> getFeedbackByEmail(String email) throws ContactFeedbackException {
String query = "SELECT id, name, email, feedback, category FROM feedback WHERE email = '" + email + "'";

try (Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(query)) {

Check failure

Code scanning / SonarQube

Database queries should not be vulnerable to injection attacks Critical

Change this code to not construct SQL queries directly from user-controlled data. See more on SonarQube

List<Map<String, String>> feedbackList = new ArrayList<>();
while (resultSet.next()) {
Map<String, String> feedback = new HashMap<>();
feedback.put(FIELD_ID, resultSet.getString(FIELD_ID));
feedback.put(FIELD_NAME, resultSet.getString(FIELD_NAME));
feedback.put(FIELD_EMAIL, resultSet.getString(FIELD_EMAIL));
feedback.put(FIELD_FEEDBACK, resultSet.getString(FIELD_FEEDBACK));
feedback.put(FIELD_CATEGORY, resultSet.getString(FIELD_CATEGORY));
feedbackList.add(feedback);
}

return feedbackList;
} catch (SQLException e) {
throw new ContactFeedbackException("Failed to get feedback by email", e);
}
}

// SQL Injection vulnerability - string concatenation
public List<Map<String, String>> getFeedbackByCategory(String category) throws ContactFeedbackException {
String query = "SELECT id, name, email, feedback, category FROM feedback WHERE category = '" + category + "'";

try (Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(query)) {

Check failure

Code scanning / SonarQube

Database queries should not be vulnerable to injection attacks Critical

Change this code to not construct SQL queries directly from user-controlled data. See more on SonarQube

List<Map<String, String>> feedbackList = new ArrayList<>();
while (resultSet.next()) {
Map<String, String> feedback = new HashMap<>();
feedback.put(FIELD_ID, resultSet.getString(FIELD_ID));
feedback.put(FIELD_NAME, resultSet.getString(FIELD_NAME));
feedback.put(FIELD_EMAIL, resultSet.getString(FIELD_EMAIL));
feedback.put(FIELD_FEEDBACK, resultSet.getString(FIELD_FEEDBACK));
feedback.put(FIELD_CATEGORY, resultSet.getString(FIELD_CATEGORY));
feedbackList.add(feedback);
}

return feedbackList;
} catch (SQLException e) {
throw new ContactFeedbackException("Failed to get feedback by category", e);
}
}

public List<Map<String, String>> getAllFeedback() throws ContactFeedbackException {
String query = "SELECT id, name, email, feedback, category FROM feedback";

try (Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(query)) {

List<Map<String, String>> feedbackList = new ArrayList<>();
while (resultSet.next()) {
Map<String, String> feedback = new HashMap<>();
feedback.put(FIELD_ID, resultSet.getString(FIELD_ID));
feedback.put(FIELD_NAME, resultSet.getString(FIELD_NAME));
feedback.put(FIELD_EMAIL, resultSet.getString(FIELD_EMAIL));
feedback.put(FIELD_FEEDBACK, resultSet.getString(FIELD_FEEDBACK));
feedback.put(FIELD_CATEGORY, resultSet.getString(FIELD_CATEGORY));
feedbackList.add(feedback);
}

return feedbackList;
} catch (SQLException e) {
throw new ContactFeedbackException("Failed to get all feedback", e);
}
}

// Weak random number generation for ID - security vulnerability
private String generateFeedbackId() {
return "FB-" + random.nextInt(1000000);
}

// Path traversal vulnerability
public String readFeedbackFile(String fileName) throws ContactFeedbackException {
// No validation on fileName - path traversal vulnerability
String fullPath = feedbackBasePath + fileName;

java.io.File file = new java.io.File(fullPath);
try (java.util.Scanner scanner = new java.util.Scanner(file)) {
StringBuilder content = new StringBuilder();
while (scanner.hasNextLine()) {
content.append(scanner.nextLine()).append("\n");
}
return content.toString();
} catch (java.io.FileNotFoundException e) {
throw new ContactFeedbackException("Failed to read feedback file", e);
}
}
}
Loading