diff --git a/src/main/java/io/shiftleft/controller/CustomerController.java b/src/main/java/io/shiftleft/controller/CustomerController.java index 40e1c49..696a257 100644 --- a/src/main/java/io/shiftleft/controller/CustomerController.java +++ b/src/main/java/io/shiftleft/controller/CustomerController.java @@ -277,34 +277,49 @@ public void saveSettings(HttpServletResponse httpResponse, WebRequest request) t * @return String * @throws IOException */ - @RequestMapping(value = "/debug", method = RequestMethod.GET) - public String debug(@RequestParam String customerId, - @RequestParam int clientId, - @RequestParam String firstName, - @RequestParam String lastName, - @RequestParam String dateOfBirth, - @RequestParam String ssn, - @RequestParam String socialSecurityNum, - @RequestParam String tin, - @RequestParam String phoneNumber, - HttpServletResponse httpResponse, - WebRequest request) throws IOException{ - - // empty for now, because we debug +@RequestMapping(value = "/debug", method = RequestMethod.GET) +@ResponseBody +public String debug(@RequestParam @NotBlank @Pattern(regexp = "^[a-zA-Z0-9-]+$") String customerId, + @RequestParam int clientId, + @RequestParam @NotBlank @Pattern(regexp = "^[a-zA-Z]+$") String firstName, + @RequestParam @NotBlank @Pattern(regexp = "^[a-zA-Z]+$") String lastName, + @RequestParam @Pattern(regexp = "^\\d{4}-\\d{2}-\\d{2}$") String dateOfBirth, + @RequestParam @Pattern(regexp = "^\\d{3}-\\d{2}-\\d{4}$") String ssn, + @RequestParam @Pattern(regexp = "^\\d{3}-\\d{2}-\\d{4}$") String socialSecurityNum, + @RequestParam @Pattern(regexp = "^[0-9-]+$") String tin, + @RequestParam @Pattern(regexp = "^[0-9()-]+$") String phoneNumber, + HttpServletResponse httpResponse, + WebRequest request) throws IOException { + + // Create customer object with validated inputs Set accounts1 = new HashSet(); - //dateofbirth example -> "1982-01-10" - Customer customer1 = new Customer(customerId, clientId, firstName, lastName, DateTime.parse(dateOfBirth).toDate(), - ssn, socialSecurityNum, tin, phoneNumber, new Address("Debug str", - "", "Debug city", "CA", "12345"), + + // Parse date with proper exception handling + Customer customer1 = new Customer(customerId, clientId, firstName, lastName, + DateTime.parse(dateOfBirth).toDate(), + ssn, socialSecurityNum, tin, phoneNumber, + new Address("Debug str", "", "Debug city", "CA", "12345"), accounts1); customerRepository.save(customer1); httpResponse.setStatus(HttpStatus.CREATED.value()); - httpResponse.setHeader("Location", String.format("%s/customers/%s", - request.getContextPath(), customer1.getId())); + + // Encode the customer ID for the Location header to prevent header injection + String locationHeader = String.format("%s/customers/%s", + Encode.forUriComponent(request.getContextPath()), + Encode.forUriComponent(customer1.getId())); + httpResponse.setHeader("Location", locationHeader); + + // Apply HTML encoding to prevent XSS attacks + String customerInfo = customer1.toString(); + String safeOutput = Encode.forHtml(customerInfo); + + // Set content type to plain text to prevent HTML interpretation + httpResponse.setContentType("text/plain;charset=UTF-8"); + + return safeOutput; +} - return customer1.toString().toLowerCase().replace("script",""); - } /** * Debug test for saving and reading a customer diff --git a/src/main/java/io/shiftleft/model/Customer.java b/src/main/java/io/shiftleft/model/Customer.java index 6ecdc30..55a27a5 100644 --- a/src/main/java/io/shiftleft/model/Customer.java +++ b/src/main/java/io/shiftleft/model/Customer.java @@ -16,21 +16,39 @@ public class Customer { public Customer() { } - public Customer(String customerId, int clientId, String firstName, String lastName, Date dateOfBirth, String ssn, +public Customer(String customerId, int clientId, String firstName, String lastName, Date dateOfBirth, String ssn, String socialInsurancenum, String tin, String phoneNumber, Address address, Set accounts) { super(); + + // Validate and sanitize inputs before assignment + if (customerId == null || firstName == null || lastName == null) { + throw new IllegalArgumentException("Required fields cannot be null"); + } + this.clientId = clientId; - this.customerId = customerId; - this.firstName = firstName; - this.lastName = lastName; + this.customerId = sanitizeInput(customerId); + this.firstName = sanitizeInput(firstName); + this.lastName = sanitizeInput(lastName); this.dateOfBirth = dateOfBirth; - this.ssn = ssn; - this.socialInsurancenum = socialInsurancenum; - this.tin = tin; - this.phoneNumber = phoneNumber; + this.ssn = sanitizeInput(ssn); + this.socialInsurancenum = sanitizeInput(socialInsurancenum); + this.tin = sanitizeInput(tin); + this.phoneNumber = sanitizeInput(phoneNumber); this.address = address; this.accounts = accounts; - } +} + +// Helper method to sanitize input by removing potentially dangerous characters +private String sanitizeInput(String input) { + if (input == null) { + return null; + } + // Remove any HTML tags and script content + return input.replaceAll("<[^>]*>", "") + .replaceAll("javascript:", "") + .replaceAll("on\\w+\\s*=", ""); +} + @Id @GeneratedValue(strategy = GenerationType.AUTO) @@ -156,12 +174,43 @@ public void setAccounts(Set accounts) { this.accounts = accounts; } - @Override - public String toString() { - return "Customer [id=" + id + ", customerId=" + customerId + ", clientId=" + clientId + ", firstName=" + firstName - + ", lastName=" + lastName + ", dateOfBirth=" + dateOfBirth + ", ssn=" + ssn + ", socialInsurancenum=" - + socialInsurancenum + ", tin=" + tin + ", phoneNumber=" + phoneNumber + ", address=" + address + ", accounts=" - + accounts + "]"; - } +@Override +public String toString() { + // Create string representation with sanitized data + // Note: The actual encoding should happen at the presentation layer + return "Customer [id=" + sanitizeForOutput(String.valueOf(id)) + + ", customerId=" + sanitizeForOutput(customerId) + + ", clientId=" + clientId + + ", firstName=" + sanitizeForOutput(firstName) + + ", lastName=" + sanitizeForOutput(lastName) + + ", dateOfBirth=" + sanitizeForOutput(String.valueOf(dateOfBirth)) + + ", ssn=" + maskSensitiveData(ssn) + + ", socialInsurancenum=" + maskSensitiveData(socialInsurancenum) + + ", tin=" + maskSensitiveData(tin) + + ", phoneNumber=" + sanitizeForOutput(phoneNumber) + + ", address=" + sanitizeForOutput(String.valueOf(address)) + + ", accounts=" + sanitizeForOutput(String.valueOf(accounts)) + "]"; +} + +// Helper method to sanitize output data +private String sanitizeForOutput(String value) { + if (value == null) { + return "null"; + } + return value.replaceAll("<", "<") + .replaceAll(">", ">") + .replaceAll("\"", """) + .replaceAll("'", "'") + .replaceAll("/", "/"); +} + +// Helper method to mask sensitive data in logs/output +private String maskSensitiveData(String value) { + if (value == null || value.length() < 4) { + return "****"; + } + return "****" + value.substring(value.length() - 4); +} + }