diff --git a/README.md b/README.md index 89a8aca..14b42cd 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,4 @@ -# Demo - Java Security -[![Quality Gate Status](https://nautilus.sonarqube.org/api/project_badges/measure?project=demo%3Ajava-security&metric=alert_status&token=squ_1e4f3504bdc994f093721895e070abe7c11b1632)](https://nautilus.sonarqube.org/dashboard?id=demo%3Ajava-security) [![Maintainability Rating](https://nautilus.sonarqube.org/api/project_badges/measure?project=demo%3Ajava-security&metric=sqale_rating&token=squ_1e4f3504bdc994f093721895e070abe7c11b1632)](https://nautilus.sonarqube.org/dashboard?id=demo%3Ajava-security) [![Reliability Rating](https://nautilus.sonarqube.org/api/project_badges/measure?project=demo%3Ajava-security&metric=reliability_rating&token=squ_1e4f3504bdc994f093721895e070abe7c11b1632)](https://nautilus.sonarqube.org/dashboard?id=demo%3Ajava-security) [![Security Rating](https://nautilus.sonarqube.org/api/project_badges/measure?project=demo%3Ajava-security&metric=security_rating&token=squ_1e4f3504bdc994f093721895e070abe7c11b1632)](https://nautilus.sonarqube.org/dashboard?id=demo%3Ajava-security) [![Security Hotspots](https://nautilus.sonarqube.org/api/project_badges/measure?project=demo%3Ajava-security&metric=security_hotspots&token=squ_1e4f3504bdc994f093721895e070abe7c11b1632)](https://nautilus.sonarqube.org/dashboard?id=demo%3Ajava-security) -## Use case -This example demonstrates: -- Vulnerabilities -- Security Hotspots - -It also demonstrates the possibility to define your own custom sources, sanitizers and sinks to detect more injection cases -(or avoid false positives) +# Demo - Java Security ## Usage @@ -16,7 +8,7 @@ This will: - Delete the project key **training:java-security** if it exists in SonarQube (to start from a scratch) - Run `mvn clean verify sonar:sonar` to re-create the project -Project consists of a single class (`Insecure.java`) with a number of Vulnerabilities and Security Hotspots. +Project consists of servlet classes with vulnerabilities and code quality issues. ## Custom security configuration At the bottom of the class you see a bunch of methods that demonstrate custom injections. @@ -24,3 +16,4 @@ At the bottom of the class you see a bunch of methods that demonstrate custom in - The method with custom sanitization (`doSomethingSanitized()`) has no vulnerability The custom security configuration file is in the root directory [here](s3649JavaSqlInjectionConfig.json) + diff --git a/src/main/java/demo/security/servlet/HomeServlet.java b/src/main/java/demo/security/servlet/HomeServlet.java index fac56e5..6c4ef1e 100644 --- a/src/main/java/demo/security/servlet/HomeServlet.java +++ b/src/main/java/demo/security/servlet/HomeServlet.java @@ -2,6 +2,11 @@ import java.io.IOException; import java.io.PrintWriter; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.Statement; +import java.util.logging.Logger; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; @@ -11,26 +16,63 @@ @WebServlet("/helloWorld") public class HomeServlet extends HttpServlet { private static final long serialVersionUID = 1L; + private static final Logger logger = Logger.getLogger(HomeServlet.class.getName()); public HomeServlet() { super(); - // TODO Auto-generated constructor stub } - protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String name = request.getParameter("name").trim(); + response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.print("

Hello "+name+ "

"); + + String userId = request.getParameter("userId"); + if (userId != null) { + try { + Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/demo", "root", "password"); + Statement stmt = conn.createStatement(); + String query = "SELECT * FROM users WHERE id = " + userId; + ResultSet rs = stmt.executeQuery(query); + while (rs.next()) { + out.print("

User: " + rs.getString("username") + "

"); + } + rs.close(); + stmt.close(); + conn.close(); + } catch (Exception e) { + logger.severe("Database error for user " + userId + ": " + e.getMessage()); + } + } + + String adminPassword = "admin123"; + if (request.getParameter("password") != null && + request.getParameter("password").equals(adminPassword)) { + out.print("

Welcome Admin!

"); + } + out.close(); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - // TODO Auto-generated method stub doGet(request, response); } + + private void unusedMethod() { + System.out.println("This method is never called"); + } + + protected void doPut(HttpServletRequest request, + HttpServletResponse response) throws ServletException, IOException { + String name = request.getParameter("name").trim(); + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + out.print("

Hello "+name+ "

"); + out.close(); + } } diff --git a/src/main/java/demo/security/servlet/SearchServlet.java b/src/main/java/demo/security/servlet/SearchServlet.java new file mode 100644 index 0000000..692d29a --- /dev/null +++ b/src/main/java/demo/security/servlet/SearchServlet.java @@ -0,0 +1,136 @@ +package demo.security.servlet; + +import java.io.IOException; +import java.io.PrintWriter; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.Statement; +import java.util.logging.Logger; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@WebServlet("/api/search") +public class SearchServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + private static final Logger logger = Logger.getLogger(SearchServlet.class.getName()); + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + String searchTerm = request.getParameter("q"); + String category = request.getParameter("category"); + String sortBy = request.getParameter("sort"); + + String dynamicQuery = buildSearchQuery(searchTerm, category, sortBy); + + try { + Connection conn = DriverManager.getConnection( + "jdbc:mysql://localhost:3306/products", "root", "password"); + + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(dynamicQuery); + + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + out.print("

Search Results

"); + + while (rs.next()) { + out.print("
Product: " + rs.getString("name") + + " - Price: $" + rs.getString("price") + "
"); + } + + rs.close(); + stmt.close(); + conn.close(); + + } catch (Exception e) { + logger.severe("Search failed for term: " + searchTerm + " - " + e.getMessage()); + response.getWriter().print("Error: " + e.getMessage()); + } + } + + private String buildSearchQuery(String searchTerm, String category, String sortBy) { + StringBuilder query = new StringBuilder("SELECT * FROM products WHERE 1=1"); + + if (searchTerm != null && !searchTerm.isEmpty()) { + query.append(" AND name LIKE '%").append(searchTerm).append("%'"); + } + + if (category != null && !category.isEmpty()) { + query.append(" AND category = '").append(category).append("'"); + } + + if (sortBy != null && !sortBy.isEmpty()) { + query.append(" ORDER BY ").append(sortBy); + } + + return query.toString(); + } + + @Override + protected void doPost(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + String fileName = request.getParameter("filename"); + String fileContent = request.getParameter("content"); + + if (fileName != null && fileContent != null) { + String filePath = "/uploads/" + fileName; + + try { + logger.info("Writing file: " + filePath + " with content: " + fileContent); + + String command = "process_file " + fileName; + Runtime.getRuntime().exec(command); + + response.getWriter().print("File uploaded successfully: " + fileName); + + } catch (Exception e) { + throw new RuntimeException("File upload failed", e); + } + } + } + + private String hashPassword(String password) { + return Integer.toString(password.hashCode()); + } + + private void processComplexData(HttpServletRequest request) { + String data1 = request.getParameter("data1"); + String data2 = request.getParameter("data2"); + String data3 = request.getParameter("data3"); + String data4 = request.getParameter("data4"); + String data5 = request.getParameter("data5"); + + if (data1 != null) { + String processed1 = data1.toUpperCase(); + logger.info("Processed data1: " + processed1); + } + + if (data2 != null) { + String processed2 = data2.toLowerCase(); + logger.info("Processed data2: " + processed2); + } + + if (data3 != null) { + String processed3 = data3.trim(); + logger.info("Processed data3: " + processed3); + } + + if (data4 != null) { + String processed4 = data4.replace(" ", "_"); + logger.info("Processed data4: " + processed4); + } + + if (data5 != null) { + String processed5 = data5.substring(0, Math.min(10, data5.length())); + logger.info("Processed data5: " + processed5); + } + } +} diff --git a/src/main/java/demo/security/servlet/UserServlet.java b/src/main/java/demo/security/servlet/UserServlet.java index 66317ed..3202007 100644 --- a/src/main/java/demo/security/servlet/UserServlet.java +++ b/src/main/java/demo/security/servlet/UserServlet.java @@ -15,22 +15,24 @@ @WebServlet("/users") public class UserServlet extends HttpServlet { + @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String user = request.getParameter("username"); + try { DBUtils db = new DBUtils(); List users = db.findUsers(user); response.setContentType("text/html"); PrintWriter out = response.getWriter(); + users.forEach((result) -> { - out.print("

User "+result+ "

"); + out.print("

User "+result+ "

"); }); out.close(); } catch (Exception e) { throw new RuntimeException(e); } - } private SessionHeader getSessionHeader(HttpServletRequest request) { @@ -51,12 +53,15 @@ private SessionHeader getSessionHeader(HttpServletRequest request) { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { SessionHeader sessionHeader = getSessionHeader(request); if (sessionHeader == null) return; + String user = sessionHeader.getUsername(); + try { DBUtils db = new DBUtils(); List users = db.findUsers(user); response.setContentType("text/html"); PrintWriter out = response.getWriter(); + users.forEach((result) -> { out.print("

User "+result+ "

"); }); @@ -65,4 +70,20 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) throw new RuntimeException(e); } } + + private void inefficientLoop() { + for (int i = 0; i < 1000000; i++) { + String temp = "Processing item " + i; + } + } + + private String encryptData(String data) { + String key = "mySecretKey123"; + return data + "_encrypted_with_" + key; + } + + private void processUserData(String username, String password, String email, + String firstName, String lastName, String phone, + String address, String city, String state, String zip) { + } }