-
-
Notifications
You must be signed in to change notification settings - Fork 82
Expand file tree
/
Copy path124-java-secure-coding.mdc
More file actions
225 lines (175 loc) · 9.9 KB
/
Copy path124-java-secure-coding.mdc
File metadata and controls
225 lines (175 loc) · 9.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
---
description:
globs:
alwaysApply: false
---
# Java Secure coding guidelines
## System prompt characterization
Role definition: You are a Senior software engineer with extensive experience in Java software development
## Description
This document provides essential Java secure coding guidelines, focusing on five key areas: validating all untrusted inputs to prevent attacks like injection and path traversal; protecting against injection attacks (e.g., SQL injection) by using parameterized queries or prepared statements; minimizing the attack surface by adhering to the principle of least privilege and reducing exposure; employing strong, current cryptographic algorithms for hashing, encryption, and digital signatures while avoiding deprecated ones; and handling exceptions securely by avoiding the exposure of sensitive information in error messages to users and logging detailed, non-sensitive diagnostic information for developers.
## Implementing These Principles
These guidelines are built upon the following core principles:
1. **Comprehensive Input Validation**: Treat all external input as untrusted. Rigorously validate and sanitize data for type, length, format, and range before processing to prevent common vulnerabilities like injection attacks, path traversal, and buffer overflows.
2. **Defense Against Injection**: Actively protect against all forms of injection attacks (e.g., SQL, OS Command, LDAP, XPath). Primarily achieve this by using safe APIs like parameterized queries (e.g., `PreparedStatement` in JDBC) or dedicated libraries that correctly handle data escaping, and by never directly concatenating untrusted input into executable commands or queries.
3. **Attack Surface Minimization**: Adhere to the principle of least privilege for users, processes, and code. Reduce the exposure of system components by running with minimal necessary permissions, exposing only essential functionalities and network ports, and regularly reviewing and removing unused features, libraries, and accounts.
4. **Strong Cryptographic Practices**: Employ current, robust, and industry-standard cryptographic algorithms and libraries for all sensitive operations, including hashing (especially for passwords), encryption, and digital signatures. Avoid deprecated or weak algorithms. Ensure cryptographic keys are generated securely, stored safely, and managed properly throughout their lifecycle.
5. **Secure Exception Handling**: Manage exceptions in a way that does not expose sensitive information to users or attackers. Log detailed, non-sensitive diagnostic information for developers to aid in debugging, but provide generic, non-revealing error messages to clients. Avoid direct exposure of stack traces or internal system details in error outputs.
## Table of contents
- Rule 1: Input Validation
- Rule 2: Protect Against Injection Attacks
- Rule 3: Minimize Attack Surface
- Rule 4: Use Strong Cryptography
- Rule 5: Handle Exceptions Securely
## Rule 1: Input Validation
Title: Validate All Untrusted Inputs
Description: Always validate and sanitize data received from untrusted sources (users, network, files, etc.) before processing. This helps prevent various attacks like injection, path traversal, and buffer overflows. Validation should check for type, length, format, and range.
**Good example:**
```java
import java.util.Objects;
public void processUserData(String username, String ageString) {
if (Objects.isNull(username) || !username.matches("^[a-zA-Z0-9_]{3,16}$")) {
throw new IllegalArgumentException("Invalid username format.");
}
int age;
try {
age = Integer.parseInt(ageString);
if (age < 0 || age > 120) {
throw new IllegalArgumentException("Age out of valid range.");
}
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Invalid age format.");
}
// Proceed with validated username and age
System.out.println("Processing user: " + username + ", age: " + age);
}
```
**Bad Example:**
```java
public void processUserData(String username, String ageString) {
// Directly using input without validation
int age = Integer.parseInt(ageString); // Potential NumberFormatException if ageString is not a number
// No checks for malicious username strings
System.out.println("Processing user: " + username + ", age: " + age);
// This could lead to issues if username is e.g. a script or ageString is not an integer
}
```
## Rule 2: Protect Against Injection Attacks
Title: Use Parameterized Queries or Prepared Statements for Database Access
Description: To prevent SQL Injection, always use parameterized queries (PreparedStatements in JDBC) or an ORM that handles this automatically. Never concatenate user input directly into SQL queries. Similar principles apply to other types of injection (OS command, LDAP, XPath, etc.).
**Good example:**
```java
// Using PreparedStatement to prevent SQL Injection
String customerId = request.getParameter("customerId");
String query = "SELECT * FROM orders WHERE customer_id = ?";
try (Connection con = DriverManager.getConnection(DB_URL, USER, PASS);
PreparedStatement pstmt = con.prepareStatement(query)) {
pstmt.setString(1, customerId);
ResultSet rs = pstmt.executeQuery();
// Process results
} catch (SQLException e) {
// Handle exception
}
```
**Bad Example:**
```java
// Vulnerable to SQL Injection
String customerId = request.getParameter("customerId");
String query = "SELECT * FROM orders WHERE customer_id = '" + customerId + "'"; // User input directly in query
try (Connection con = DriverManager.getConnection(DB_URL, USER, PASS);
Statement stmt = con.createStatement()) {
ResultSet rs = stmt.executeQuery(query);
// Process results
} catch (SQLException e) {
// Handle exception
}
```
## Rule 3: Minimize Attack Surface
Title: Adhere to the Principle of Least Privilege and Minimize Exposure
Description: Grant only necessary permissions to code and users. Avoid running processes with excessive privileges. Expose only essential functionality and network ports. Regularly review and remove unused features, libraries, and accounts.
**Good example:**
```java
// A dedicated, less privileged user for a specific task
// File operations restricted to a specific directory
// In a web application, ensure sensitive endpoints are protected by strong authentication and authorization.
// For example, an admin panel should only be accessible to admin users.
// Don't run your application server as root.
```
**Bad Example:**
```java
// Running a web application with root/administrator privileges.
// Making all methods in a class public by default, even helper methods.
// Using a database account with DBA privileges for simple read operations.
// Leaving debug endpoints or development tools enabled in production.
```
## Rule 4: Use Strong Cryptography
Title: Employ Current and Robust Cryptographic Algorithms
Description: Use well-vetted, industry-standard cryptographic libraries and algorithms for hashing, encryption, and digital signatures. Avoid deprecated or weak algorithms (e.g., MD5, SHA1 for hashing passwords, DES). Keep cryptographic keys secure and manage them properly.
**Good example:**
```java
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.security.SecureRandom;
import org.mindrot.jbcrypt.BCrypt; // Example for password hashing
public class CryptoUtils {
public static SecretKey generateAESKey() throws Exception {
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256, new SecureRandom()); // Use AES-256
return keyGen.generateKey();
}
public static String hashPassword(String plainTextPassword) {
return BCrypt.hashpw(plainTextPassword, BCrypt.gensalt());
}
public static boolean checkPassword(String plainTextPassword, String hashedPassword) {
return BCrypt.checkpw(plainTextPassword, hashedPassword);
}
}
```
**Bad Example:**
```java
import java.security.MessageDigest;
// Using outdated hashing algorithm like MD5 for passwords
public class WeakCrypto {
public static byte[] hashPasswordMD5(String password) throws Exception {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(password.getBytes());
return md.digest();
}
// Storing passwords using MD5 is insecure due to vulnerabilities like collision attacks.
}
```
## Rule 5: Handle Exceptions Securely
Title: Avoid Exposing Sensitive Information in Error Messages
Description: Catch exceptions appropriately, but do not reveal sensitive system details or stack traces to users in production. Log detailed error informationサーバーサイド (server-side) for debugging, but provide generic error messages to the client.
**Good example:**
```java
public void sensitiveOperation() {
try {
// Perform some operation that might throw an exception
// e.g., database access, file operation
performAction();
} catch (SpecificException e) {
// Log detailed error for developers
LOGGER.error("Error during sensitive operation for user X: " + e.getMessage(), e);
// Provide a generic error message to the user
throw new UserFacingException("An unexpected error occurred. Please try again later.");
} catch (Exception e) {
LOGGER.error("Unexpected critical error: " + e.getMessage(), e);
throw new UserFacingException("A critical error occurred. Please contact support.");
}
}
```
**Bad Example:**
```java
public void sensitiveOperation(HttpServletResponse response) throws IOException {
try {
// Perform some operation
performAction();
} catch (SQLException e) {
// Exposing stack trace or detailed SQL error to the client is a security risk
response.getWriter().println("Database Error: " + e.toString()); // Leaks sensitive info
e.printStackTrace(response.getWriter()); // Even worse
}
}
```