move query out of experimental

This commit is contained in:
Alvaro Muñoz
2020-10-27 14:27:26 +01:00
parent df4164f2c0
commit 2bab9d22e9
3 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,48 @@
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import org.hibernate.validator.constraintvalidation.HibernateConstraintValidatorContext;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class TestValidator implements ConstraintValidator<Object, String> {
public static class InterpolationHelper {
public static final char BEGIN_TERM = '{';
public static final char END_TERM = '}';
public static final char EL_DESIGNATOR = '$';
public static final char ESCAPE_CHARACTER = '\\';
private static final Pattern ESCAPE_MESSAGE_PARAMETER_PATTERN = Pattern.compile( "([\\" + ESCAPE_CHARACTER + BEGIN_TERM + END_TERM + EL_DESIGNATOR + "])" );
private InterpolationHelper() {
}
public static String escapeMessageParameter(String messageParameter) {
if ( messageParameter == null ) {
return null;
}
return ESCAPE_MESSAGE_PARAMETER_PATTERN.matcher( messageParameter ).replaceAll( Matcher.quoteReplacement( String.valueOf( ESCAPE_CHARACTER ) ) + "$1" );
}
}
@Override
public boolean isValid(String object, ConstraintValidatorContext constraintContext) {
String value = object + " is invalid";
// Bad: Bean properties (normally user-controlled) are passed directly to `buildConstraintViolationWithTemplate`
constraintContext.buildConstraintViolationWithTemplate(value).addConstraintViolation().disableDefaultConstraintViolation();
// Good: Bean properties (normally user-controlled) are escaped
String escaped = InterpolationHelper.escapeMessageParameter(value);
constraintContext.buildConstraintViolationWithTemplate(escaped).addConstraintViolation().disableDefaultConstraintViolation();
// Good: Bean properties (normally user-controlled) are parameterized
HibernateConstraintValidatorContext context = constraintContext.unwrap( HibernateConstraintValidatorContext.class );
context.addMessageParameter( "prop", object );
context.buildConstraintViolationWithTemplate( "{prop} is invalid").addConstraintViolation();
return false;
}
}

View File

@@ -0,0 +1,46 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Bean validation custom constraint error messages support different types of interpolation,
including <a href="https://docs.jboss.org/hibernate/validator/5.1/reference/en-US/html/chapter-message-interpolation.html#section-interpolation-with-message-expressions">Java EL expressions</a>.
Controlling part of the message template being passed to `ConstraintValidatorContext.buildConstraintViolationWithTemplate()`
argument will lead to arbitrary Java code execution. Unfortunately, it is common that validated (and therefore, normally
untrusted) bean properties flow into the custom error message.</p>
</overview>
<recommendation>
<p>There are different approaches to remediate the issue:</p>
<li>Do not include validated bean properties in the custom error message.</li>
<li>Use parameterized messages instead of string concatenation. E.g:</li>
``` java
HibernateConstraintValidatorContext context = constraintValidatorContext.unwrap( HibernateConstraintValidatorContext.class );
context.addMessageParameter( "foo", "bar" );
context.buildConstraintViolationWithTemplate( "My violation message contains a parameter {foo}").addConstraintViolation();
```
<li>Sanitize the validated bean properties to make sure that there are no EL expressions. An example of valid sanitization
logic can be found <a href="https://github.com/hibernate/hibernate-validator/blob/master/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/util/InterpolationHelper.java#L17">here</a>.
- Disable the EL interpolation and only use `ParameterMessageInterpolator`:</li>
``` java
Validator validator = Validation.byDefaultProvider()
.configure()
.messageInterpolator( new ParameterMessageInterpolator() )
.buildValidatorFactory()
.getValidator();
```
<li>Replace Hibernate-Validator with Apache BVal which in its latest version does not interpolate EL expressions by default.
Note that this replacement may not be a simple drop-in replacement.</li>
</recommendation>
<example>
<p>The following Validator could result in arbitrary Java code execution:</p>
<sample src="InsecureBeanValidation.java" />
</example>
<references>
<li>https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#_the_code_constraintvalidatorcontext_code</li>
<li>https://securitylab.github.com/research/bean-validation-RCE</li>
</references>
</qhelp>

View File

@@ -0,0 +1,58 @@
/**
* @name Insecure Bean validation
* @description User-controlled data may be evaluated as a Java EL expressions, leading to arbitrary code execution.
* @kind path-problem
* @problem.severity error
* @precision high
* @id java/unsafe-eval
* @tags security
* external/cwe/cwe-094
*/
import java
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.dataflow.FlowSources
import DataFlow::PathGraph
class BeanValidationSource extends RemoteFlowSource {
BeanValidationSource() {
exists(Method m, Parameter v |
this.asParameter() = v and
m.getParameter(0) = v and
m
.getDeclaringType()
.getASourceSupertype+()
.hasQualifiedName("javax.validation", "ConstraintValidator") and
m.hasName("isValid") and
m.fromSource()
)
}
override string getSourceType() { result = "BeanValidation source" }
}
class BuildConstraintViolationWithTemplateMethod extends Method {
BuildConstraintViolationWithTemplateMethod() {
this.getDeclaringType()
.getASupertype*()
.hasQualifiedName("javax.validation", "ConstraintValidatorContext") and
this.hasName("buildConstraintViolationWithTemplate")
}
}
class BeanValidationConfig extends TaintTracking::Configuration {
BeanValidationConfig() { this = "BeanValidationConfig" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) {
exists(MethodAccess ma |
ma.getMethod() instanceof BuildConstraintViolationWithTemplateMethod and
sink.asExpr() = ma.getArgument(0)
)
}
}
from BeanValidationConfig cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink, source, sink, "Custom constraint error message contains unsanitized user data"