What is the Input Validation Framework?
The Input Validation Framework is a centralized security framework used to validate that external input is provided in the expected format. Validating user input is critical because it is the basis for generated HTML and REST API output, used in the construction of SQL queries, used to access files, etc. Malicious input can be used to compromise the security of a Sugar instance and the underlying infrastructure. The validation framework provides better control than the pre-existing input sanitization techniques applied to user input within Sugar.
Fixing Input Validation problems
Sugar’s input validation was enabled but only logging failures as warnings into the sugarcrm.log file since the 7.7.1 release. With the Winter ‘18 release, the validation.soft_fail configuration setting will now default to false. This means that input validation checks will be strictly enforced by default instead of simply logging warning messages.
For more information about using validation constraints in your own custom code, check out the Sugar Developer Guide, the previous UnCon Security presentation, or the Winter '18 webinar.
Identifying input validation violations
Beginning in the Winter ‘18 release, input validation violations are reported as PHP Fatal errors in the PHP error log and Critical error messages in sugarcrm.log file. Invalid requests will generally be terminated with an HTTP 500 error as well.
Let’s walk through an example of an input validation violation.
In this example, we have a customization that is accessing the Sugar instance at the following URL: sugarcrm/ult/#bwc/index.php?module=xxxxx.
If xxxxx is not a registered module, there will be a FATAL error in the PHP error log.
For example,
[15-Jan-2018 22:04:09] WARNING: [pool www] child 1940 said into stderr: "NOTICE: PHP message: PHP Fatal error: Uncaught exception 'Sugarcrm\Sugarcrm\Security\InputValidation\Exception\ViolationException' with message 'Violation for REQUEST -> module' in /srv/www/<instance>/prebuild/test/ult/sugarcrm/src/Security/InputValidation/Request.php:280"
[15-Jan-2018 22:04:09] WARNING: [pool www] child 1940 said into stderr: "Stack trace:"
[15-Jan-2018 22:04:09] WARNING: [pool www] child 1940 said into stderr: "#0 /srv/www/<instance>/prebuild/test/ult/sugarcrm/src/Security/InputValidation/Request.php(209): Sugarcrm\Sugarcrm\Security\InputValidation\Request->handleViolations('REQUEST', 'module')"...
The sugarcrm.log will also show an error.
For example,
Tue Jan 16 06:05:18 2018 [1941][-none-][CRITICAL] InputValidation: [REQUEST] module -> Invalid module xxxxx
From the end user perspective, these fatal errors will cause pages to appear blank or stalled during loading. If you inspect the browser console when this happens, you will likely see HTTP errors logged.
Fixing input validation violations
The steps to take to fix the violation are going to depend on the exact constraint that you are violating. Luckily the exceptions you find in the PHP error log and the messages in the sugarcrm.log will indicate the constraint that you are violating.
In the above example, attempting to access a BWC view for an unregistered custom module “xxxxx” is causing the failure. If you make sure that the module you are using is properly registered in Sugar’s module list, or modify your request to use an existing Sugar module, then this will fix this issue since the constraint is checking if the module name is a known modules installed in this Sugar instance.
There are basic Symfony framework PHP constraints that we use. These do not need an in depth explanation. The basic Symfony constraints can be used to validate URLs, date time formats, etc. Check out the Symfony documentation for these basic constraints.
In Sugar's implementation, we add our own set of validation constraints. These constraints extend from Symfony's Constraint and ConstraintValidator classes and are located in the ./src/Security/Validator/Constraints directory of your Sugar installation. Each Constraint is enforced using a related Validator class. You can inspect the Validator classes to see the precise logic that needs to be followed. For example, the Bean/ModuleName constraint is implemented by the Bean/ModuleNameValidator class. This constraint is used to ensure that the input is a string that matches the name of a valid module with an associated SugarBean class.
One of the basic rules that most of these constraints implement is that an input type should be a scalar. This means we expect most user input to be integer, decimal, string, or boolean values.
Sugar Constraints
The list provided below may not be exhaustive.
- Bean/ModuleName
- Must be a string. The Module’s SugarBean class must be retrievable using BeanFactory. For example, this is used in legacy Workflow.
- ComponentName
- Must start with a letter and may only consist of letters, numbers, hyphens and underscores. For example, this is used throughout Studio and Module Builder for module names, package names, and Sugar Logic functions.
- Delimited
- By default, must be comma delimited scalar values. For example, this is used in conjunction with other constraints.
- DropdownList
- Dropdown lists must only consist of letters, numbers and underscores. For example, this is applied to dropdown lists during module install.
- File
- File must exist in an allowed file path and must not include null characters or any directory traversals. For example, this is used by FileLoader utility class.
- Guid
- Must be a string with alphanumeric or dash characters. For example, this is used with SugarMVC Views.
- InputParameters
- General input validation for GET, POST, REQUEST superglobals. Must be scalar values and strings should not contain null characters.
- JSON
- Must be a string that is JSON decodable. Returns decoded PHP associative array. For example, used in Configure Navigation Bar Quick Create.
- Language
- Must be a locale code that matches an installed language. For example, this is applied where languages can be selected in UI.
- LegacyCleanString
- Reimplements input sanitization rules previously used with clean_string() function.
- Mvc/ModuleName
- Must be a string. A more permissive test than Bean/ModuleName that allows any module name that can be found in global module lists. For example, this is used throughout SugarMVC Views.
- PhpSerialized
- Must be a PHP serialized string that does not contain objects. Returns unserialized value.
- Platform
- Must be a string that is under 128 characters and contains alphanumeric and dash characters. Must be a known Platform value such as “base”, “mobile”, “portal”, etc., or one registered using Platform extension. For example, this is used to validate REST API login requests.
- Sql/OrderBy
- Must be a string that represents a valid ORDER BY SQL clause. For example, this is used in SugarMVC list views.
- Sql/OrderDirection
- Must be a string that is uses SQL keywords “ASC” or “DESC”. For example, this is used in SugarMVC list views.
- SugarLogic/FunctionName
- Must be a string that only uses word characters and dashes. For example, this is used in Sugar Studio.
If you encounter a failure, then you should be able to identify the constraint that you are violating from your error logs. By looking at log messages that appear immediately before the failure, and possibly some exploration in the Sugar user interface, you will be able to identify the failing request. From there, you can use the information above to alter the request to comply with the necessary constraints.
This is not a substitute for Sugar field level validation!
An important thing to note about the Input Validation Framework is that it is not the only input validation mechanism available. For example, there is still separate field level validation that occurs when users create or edit records. Sidecar customizations or Studio configuration can still be used to perform validation of user provided input for each field of a record in a user friendly way. For example, Sugar will let you save a record without filling out required fields and will display a user friendly warning that tells user what to correct. The Input Validation Framework is centered around security and does not provide the same usability than you would get validating user input using Sidecar or Studio settings.