Skip to content

Commit 50a3f5a

Browse files
author
root
committed
feat: Add comprehensive SonarQube demo issues
- Add SQL injection vulnerabilities with taint analysis examples - Include XSS vulnerabilities with unescaped user input - Add path traversal and command injection issues - Include security hotspots (hardcoded passwords, weak crypto) - Add code quality issues (dead code, duplicated code, magic numbers) - Create complex data flow examples for taint analysis demos - Add deserialization vulnerabilities and information disclosure - Include performance issues and code smells - Update README with comprehensive demo guide for sales engineers Perfect for demonstrating SonarQube's comprehensive analysis capabilities including taint analysis, security hotspots, and code quality metrics.
1 parent 6884f23 commit 50a3f5a

File tree

4 files changed

+308
-9
lines changed

4 files changed

+308
-9
lines changed

README.md

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,44 @@
11
# Demo - Java Security
22
[![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)
3+
34
## Use case
45
This example demonstrates:
5-
- Vulnerabilities
6-
- Security Hotspots
6+
- **Vulnerabilities** (including SQL Injection, XSS, Path Traversal)
7+
- **Security Hotspots** (hardcoded passwords, weak crypto, unsafe deserialization)
8+
- **Taint Analysis Issues** (complex data flow vulnerabilities)
9+
- **Code Quality Issues** (dead code, duplicated code, magic numbers)
10+
11+
Perfect for **SonarQube sales demos** showcasing comprehensive security analysis capabilities.
12+
13+
## SonarQube Issues Included
14+
15+
### 🔴 Security Vulnerabilities
16+
- **SQL Injection**: Direct string concatenation in SQL queries
17+
- **Cross-Site Scripting (XSS)**: Unescaped user input in HTML output
18+
- **Path Traversal**: User input used in file paths
19+
- **Command Injection**: User input passed to system commands
20+
- **Deserialization Vulnerabilities**: Unsafe object deserialization
21+
- **Information Disclosure**: Sensitive data in error messages
22+
23+
### 🟡 Security Hotspots
24+
- **Hardcoded Passwords**: Plaintext passwords in source code
25+
- **Weak Cryptographic Algorithms**: Insecure hashing methods
26+
- **Unsafe Deserialization**: ObjectInputStream without validation
727

8-
It also demonstrates the possibility to define your own custom sources, sanitizers and sinks to detect more injection cases
9-
(or avoid false positives)
28+
### 🔵 Code Quality Issues
29+
- **Null Pointer Vulnerabilities**: Missing null checks
30+
- **Dead Code**: Unreachable code and unused methods
31+
- **Code Duplication**: Repeated logic across methods
32+
- **Magic Numbers**: Hardcoded numeric values
33+
- **Long Methods**: Methods with too many responsibilities
34+
- **Too Many Parameters**: Methods with excessive parameters
35+
- **Generic Exception Handling**: Catching Exception instead of specific types
36+
37+
### 🟢 Taint Analysis Examples
38+
- **Complex Data Flow**: User input flowing through multiple methods to SQL queries
39+
- **String Concatenation**: Taint propagation through string building
40+
- **Session Data**: Untrusted session data used without validation
41+
- **File Operations**: User input affecting file system operations
1042

1143
## Usage
1244

@@ -16,11 +48,21 @@ This will:
1648
- Delete the project key **training:java-security** if it exists in SonarQube (to start from a scratch)
1749
- Run `mvn clean verify sonar:sonar` to re-create the project
1850

19-
Project consists of a single class (`Insecure.java`) with a number of Vulnerabilities and Security Hotspots.
51+
Project consists of multiple servlet classes with intentional vulnerabilities and code quality issues perfect for demonstrating SonarQube's analysis capabilities.
2052

2153
## Custom security configuration
2254
At the bottom of the class you see a bunch of methods that demonstrate custom injections.
2355
- The method without sanitization (`doSomething()`) has an injection vulnerability
2456
- The method with custom sanitization (`doSomethingSanitized()`) has no vulnerability
2557

2658
The custom security configuration file is in the root directory [here](s3649JavaSqlInjectionConfig.json)
59+
60+
## Sales Demo Tips
61+
62+
This project is specifically designed for SonarQube sales demonstrations:
63+
64+
1. **Show Taint Analysis**: Demonstrate how SonarQube tracks data flow from user input to vulnerable sinks
65+
2. **Highlight Security Hotspots**: Show the difference between vulnerabilities and security hotspots
66+
3. **Code Quality**: Demonstrate maintainability and reliability issues
67+
4. **Custom Rules**: Show how custom sources, sanitizers, and sinks can be configured
68+
5. **Real-time Analysis**: Run analysis during the demo to show immediate feedback

src/main/java/demo/security/servlet/HomeServlet.java

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
import java.io.IOException;
44
import java.io.PrintWriter;
5+
import java.sql.Connection;
6+
import java.sql.DriverManager;
7+
import java.sql.ResultSet;
8+
import java.sql.Statement;
9+
import java.util.logging.Logger;
510
import javax.servlet.ServletException;
611
import javax.servlet.annotation.WebServlet;
712
import javax.servlet.http.HttpServlet;
@@ -11,26 +16,73 @@
1116
@WebServlet("/helloWorld")
1217
public class HomeServlet extends HttpServlet {
1318
private static final long serialVersionUID = 1L;
19+
private static final Logger logger = Logger.getLogger(HomeServlet.class.getName());
1420

1521
public HomeServlet() {
1622
super();
1723
// TODO Auto-generated constructor stub
1824
}
1925

20-
2126
protected void doGet(HttpServletRequest request,
2227
HttpServletResponse response) throws ServletException, IOException {
28+
// SonarQube Issue: Null pointer vulnerability - no null check
2329
String name = request.getParameter("name").trim();
30+
31+
// SonarQube Issue: XSS vulnerability - direct output without escaping
2432
response.setContentType("text/html");
2533
PrintWriter out = response.getWriter();
2634
out.print("<h2>Hello "+name+ "</h2>");
35+
36+
// SonarQube Issue: SQL Injection vulnerability - taint analysis will catch this
37+
String userId = request.getParameter("userId");
38+
if (userId != null) {
39+
try {
40+
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/demo", "root", "password");
41+
Statement stmt = conn.createStatement();
42+
// This is a classic SQL injection - taint analysis will flag this
43+
String query = "SELECT * FROM users WHERE id = " + userId;
44+
ResultSet rs = stmt.executeQuery(query);
45+
while (rs.next()) {
46+
out.print("<p>User: " + rs.getString("username") + "</p>");
47+
}
48+
rs.close();
49+
stmt.close();
50+
conn.close();
51+
} catch (Exception e) {
52+
// SonarQube Issue: Information disclosure - logging sensitive data
53+
logger.severe("Database error for user " + userId + ": " + e.getMessage());
54+
}
55+
}
56+
57+
// SonarQube Issue: Hardcoded password
58+
String adminPassword = "admin123";
59+
if (request.getParameter("password") != null &&
60+
request.getParameter("password").equals(adminPassword)) {
61+
out.print("<h3>Welcome Admin!</h3>");
62+
}
63+
2764
out.close();
2865
}
2966

3067
protected void doPost(HttpServletRequest request,
3168
HttpServletResponse response) throws ServletException, IOException {
32-
// TODO Auto-generated method stub
69+
// SonarQube Issue: Empty method - code smell
3370
doGet(request, response);
3471
}
72+
73+
// SonarQube Issue: Dead code - unused method
74+
private void unusedMethod() {
75+
System.out.println("This method is never called");
76+
}
77+
78+
// SonarQube Issue: Duplicated code - same logic as doGet
79+
protected void doPut(HttpServletRequest request,
80+
HttpServletResponse response) throws ServletException, IOException {
81+
String name = request.getParameter("name").trim();
82+
response.setContentType("text/html");
83+
PrintWriter out = response.getWriter();
84+
out.print("<h2>Hello "+name+ "</h2>");
85+
out.close();
86+
}
3587

3688
}
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
package demo.security.servlet;
2+
3+
import java.io.IOException;
4+
import java.io.PrintWriter;
5+
import java.sql.Connection;
6+
import java.sql.DriverManager;
7+
import java.sql.PreparedStatement;
8+
import java.sql.ResultSet;
9+
import java.sql.Statement;
10+
import java.util.logging.Logger;
11+
import javax.servlet.ServletException;
12+
import javax.servlet.annotation.WebServlet;
13+
import javax.servlet.http.HttpServlet;
14+
import javax.servlet.http.HttpServletRequest;
15+
import javax.servlet.http.HttpServletResponse;
16+
17+
@WebServlet("/api/search")
18+
public class SearchServlet extends HttpServlet {
19+
private static final long serialVersionUID = 1L;
20+
private static final Logger logger = Logger.getLogger(SearchServlet.class.getName());
21+
22+
@Override
23+
protected void doGet(HttpServletRequest request, HttpServletResponse response)
24+
throws ServletException, IOException {
25+
26+
// SonarQube Issue: Taint Analysis - Complex data flow vulnerability
27+
String searchTerm = request.getParameter("q");
28+
String category = request.getParameter("category");
29+
String sortBy = request.getParameter("sort");
30+
31+
// This creates a taint flow from user input to SQL query
32+
String dynamicQuery = buildSearchQuery(searchTerm, category, sortBy);
33+
34+
try {
35+
Connection conn = DriverManager.getConnection(
36+
"jdbc:mysql://localhost:3306/products", "root", "password");
37+
38+
// SonarQube Issue: SQL Injection - taint analysis will catch this
39+
Statement stmt = conn.createStatement();
40+
ResultSet rs = stmt.executeQuery(dynamicQuery);
41+
42+
response.setContentType("text/html");
43+
PrintWriter out = response.getWriter();
44+
out.print("<h2>Search Results</h2>");
45+
46+
while (rs.next()) {
47+
// SonarQube Issue: XSS vulnerability - direct output
48+
out.print("<div>Product: " + rs.getString("name") +
49+
" - Price: $" + rs.getString("price") + "</div>");
50+
}
51+
52+
rs.close();
53+
stmt.close();
54+
conn.close();
55+
56+
} catch (Exception e) {
57+
// SonarQube Issue: Information disclosure in error message
58+
logger.severe("Search failed for term: " + searchTerm + " - " + e.getMessage());
59+
response.getWriter().print("Error: " + e.getMessage());
60+
}
61+
}
62+
63+
// SonarQube Issue: Taint Analysis - This method propagates taint
64+
private String buildSearchQuery(String searchTerm, String category, String sortBy) {
65+
StringBuilder query = new StringBuilder("SELECT * FROM products WHERE 1=1");
66+
67+
if (searchTerm != null && !searchTerm.isEmpty()) {
68+
// Taint flows through string concatenation
69+
query.append(" AND name LIKE '%").append(searchTerm).append("%'");
70+
}
71+
72+
if (category != null && !category.isEmpty()) {
73+
// Taint flows through string concatenation
74+
query.append(" AND category = '").append(category).append("'");
75+
}
76+
77+
if (sortBy != null && !sortBy.isEmpty()) {
78+
// Taint flows through string concatenation - ORDER BY injection
79+
query.append(" ORDER BY ").append(sortBy);
80+
}
81+
82+
return query.toString();
83+
}
84+
85+
@Override
86+
protected void doPost(HttpServletRequest request, HttpServletResponse response)
87+
throws ServletException, IOException {
88+
89+
// SonarQube Issue: Taint Analysis - File upload vulnerability
90+
String fileName = request.getParameter("filename");
91+
String fileContent = request.getParameter("content");
92+
93+
if (fileName != null && fileContent != null) {
94+
// SonarQube Issue: Path Traversal - taint analysis will catch this
95+
String filePath = "/uploads/" + fileName;
96+
97+
try {
98+
// Simulate file writing (in real app, this would write to filesystem)
99+
logger.info("Writing file: " + filePath + " with content: " + fileContent);
100+
101+
// SonarQube Issue: Command Injection - taint analysis will catch this
102+
String command = "process_file " + fileName;
103+
Runtime.getRuntime().exec(command);
104+
105+
response.getWriter().print("File uploaded successfully: " + fileName);
106+
107+
} catch (Exception e) {
108+
// SonarQube Issue: Generic exception handling
109+
throw new RuntimeException("File upload failed", e);
110+
}
111+
}
112+
}
113+
114+
// SonarQube Issue: Security Hotspot - Weak cryptographic algorithm
115+
private String hashPassword(String password) {
116+
// This would be flagged as a security hotspot
117+
return Integer.toString(password.hashCode());
118+
}
119+
120+
// SonarQube Issue: Code Smell - Long method
121+
private void processComplexData(HttpServletRequest request) {
122+
String data1 = request.getParameter("data1");
123+
String data2 = request.getParameter("data2");
124+
String data3 = request.getParameter("data3");
125+
String data4 = request.getParameter("data4");
126+
String data5 = request.getParameter("data5");
127+
128+
// Process data1
129+
if (data1 != null) {
130+
String processed1 = data1.toUpperCase();
131+
logger.info("Processed data1: " + processed1);
132+
}
133+
134+
// Process data2
135+
if (data2 != null) {
136+
String processed2 = data2.toLowerCase();
137+
logger.info("Processed data2: " + processed2);
138+
}
139+
140+
// Process data3
141+
if (data3 != null) {
142+
String processed3 = data3.trim();
143+
logger.info("Processed data3: " + processed3);
144+
}
145+
146+
// Process data4
147+
if (data4 != null) {
148+
String processed4 = data4.replace(" ", "_");
149+
logger.info("Processed data4: " + processed4);
150+
}
151+
152+
// Process data5
153+
if (data5 != null) {
154+
String processed5 = data5.substring(0, Math.min(10, data5.length()));
155+
logger.info("Processed data5: " + processed5);
156+
}
157+
}
158+
}

0 commit comments

Comments
 (0)