// SECURE: Parameterized JdbcTemplate queries with validation
@Service
public class UserService {
@Autowired
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
// Whitelisted values for security
private static final Set<String> VALID_SEARCH_COLUMNS = Set.of(
"name", "email", "department", "age", "status"
);
public List<Map<String, Object>> searchUsersWithFilters(Map<String, String> filters) {
StringBuilder sql = new StringBuilder("SELECT id, name, email, department, age, status FROM users WHERE 1=1");
Map<String, Object> params = new HashMap<>();
// Process filters with validation
for (Map.Entry<String, String> filter : filters.entrySet()) {
String column = filter.getKey();
String value = filter.getValue();
// Validate column name
if (!VALID_SEARCH_COLUMNS.contains(column)) {
throw new IllegalArgumentException("Invalid filter column: " + column);
}
// Validate value
if (value == null || value.trim().isEmpty()) {
continue;
}
switch (column) {
case "name":
sql.append(" AND name LIKE :name");
params.put("name", "%" + value + "%");
break;
case "age":
try {
int age = Integer.parseInt(value);
if (age < 0 || age > 150) {
throw new IllegalArgumentException("Invalid age range");
}
sql.append(" AND age = :age");
params.put("age", age);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Invalid age format");
}
break;
default:
sql.append(" AND ").append(column).append(" = :").append(column);
params.put(column, value);
break;
}
}
sql.append(" LIMIT 1000"); // Prevent excessive results
return namedParameterJdbcTemplate.queryForList(sql.toString(), params);
}
}