Proper input validation can ensure that malicious data is not inserted into the system. However, it fails to provide the assurance that validated data will remain consistent throughout its lifetime. For instance, if an insider is allowed to insert data into a database without validation, it is possible to glean unauthorized information or execute arbitrary code on the client side by means of attacks such as Cross Site Scripting (XSS). Consequently, output filtering is as important as input validation.
As with input validation, data must be normalized before it is filtered for malicious characters. To ensure that any data that bypasses the validation does not cause vulnerabilities, it is highly recommended that output characters be encoded, except those that are known to be safe.
...
Code Block | ||
---|---|---|
| ||
public class BadOutput { public static void display() { // description and input are String variables containing values obtained from a database // description = "description" and input = "<script> executable XSScode </script>" public static void display(String description, String input) { // displayDisplay to the user or pass description and input to another system } } |
...
Wiki Markup |
---|
This compliant solution defines a {{ValidateOutput}} class that normalizes the output to a known character set, performs output validation using a whitelistwhite-list and encodes any non-specified data values to enforce a double checking mechanism. Different fields may require different whitelistingwhite-listing patterns. \[[OWASP 08|AA. Java References#OWASP 08]\] |
Code Block | ||
---|---|---|
| ||
public class ValidateOutput { // allowsAllows only alphanumeric characters and spaces private Pattern pattern = Pattern.compile("^[a-zA-Z0-9\\s]{0,20}$"); // validatesValidates and encodes the input field based on a whitelist private String validate(String name, String input) throws ValidationException { String canonical = normalize(input); if(!pattern.matcher(canonical).matches()) { throw new ValidationException( "Improper format in " + name + " field"); } // performsPerforms output encoding for non valid characters canonical = HTMLEntityEncode(canonical); return canonical; } // normalizesNormalizes to known instances private String normalize(String input) { String canonical = java.text.Normalizer.normalize(input, Normalizer.Form.NFKC); return canonical; } // Encodes non valid data public static String HTMLEntityEncode(String input) { StringBuffer sb = new StringBuffer(); for (int i = 0;i < input.length();++i) { char ch = input.charAt(i); if (Character.isLetterOrDigit(ch) || Character.isWhitespace(ch)) { sb.append(ch); } else { sb.append("&#" + (int)ch + ";"); } } return sb.toString(); } public static void display() throws ValidationException { // description and input are String variables containing values obtained from a database // description = "description" and input = "2 items available" public static void display(String description, String input) throws ValidationException { ValidateOutput vo = new ValidateOutput(); vo.validate(description, input); // passPass to another systemsubsystem or display to the user } } |
...