Skip to content

Commit

Permalink
- Made BlazeDS use the ClassDeserializationValidator as default valid…
Browse files Browse the repository at this point in the history
…ator, if no validator is provided.

- Adjusted the classes in the ClassDeserializationValidator default classes to explicitly list each class instead of using wildcards.

If you are getting errors, you need to explicitly list the classes you want to allow:

```
<services-config>
    <validators>
        <validator class="flex.messaging.validators.ClassDeserializationValidator">
            <properties>
                <allow-classes>
                    <class name="remoting.amfclient.ClientCustomType"/>
                    <class name="remoting.amfclient.ServerCustomType"/>
                    <class name="my.package.*"/>
                </allow-classes>
            </properties>
        </validator>
    </validators>

    ... snip ...

</services-config>
```
  • Loading branch information
Christofer Dutz committed Feb 17, 2017
1 parent e8560ab commit f861f09
Show file tree
Hide file tree
Showing 9 changed files with 366 additions and 148 deletions.
1 change: 1 addition & 0 deletions core/src/main/java/flex/messaging/MessageBroker.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
import flex.messaging.util.StringUtils;
import flex.messaging.util.UUIDGenerator;
import flex.messaging.util.UUIDUtils;
import flex.messaging.validators.ClassDeserializationValidator;
import flex.messaging.validators.DeserializationValidator;

import javax.servlet.ServletContext;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*/
package flex.messaging.config;

import flex.messaging.validators.ClassDeserializationValidator;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
Expand Down Expand Up @@ -1865,21 +1866,37 @@ private void messageFilter(Node messageFilter, String filterType)
private void validators(Node root)
{
Node validatorsNode = selectSingleNode(root, VALIDATORS_ELEMENT);
if (validatorsNode == null)
if (validatorsNode == null) {
// Default to the ClassDeserializationValidator
defaultValidator();
return;
}

// Validation
allowedChildElements(validatorsNode, VALIDATORS_CHILDREN);

// Validator
NodeList validators = selectNodeList(validatorsNode, VALIDATOR_ELEMENT);
for (int i = 0; i < validators.getLength(); i++)
{
Node validator = validators.item(i);
validator(validator);
if(validators.getLength() > 0) {
for (int i = 0; i < validators.getLength(); i++) {
Node validator = validators.item(i);
validator(validator);
}
} else {
// Default to the ClassDeserializationValidator
defaultValidator();
}
}

/**
* Initialize a efault validator that protects BlazeDS against the most obvious attacks.
*/
private void defaultValidator() {
ValidatorSettings validatorSettings = new ValidatorSettings();
validatorSettings.setClassName(ClassDeserializationValidator.class.getName());
((MessagingConfiguration)config).addValidatorSettings(validatorSettings);
}

private void validator(Node validator)
{
// Validation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package flex.messaging.io;

import flex.messaging.util.ClassUtil;
import flex.messaging.validators.ClassDeserializationValidator;
import flex.messaging.validators.DeserializationValidator;

import java.io.Serializable;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,18 @@
*/
package flex.messaging.validators;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

import flex.messaging.config.ConfigMap;

import java.util.*;
import java.util.regex.Pattern;

/**
* The <code>ClassDeserializationValidator</code> is provided as a default
* implementation of <code>DeserializationValidator</code> and it simply
* validates the creation of allowed and disallowed classes as specified in
* the configuration.
*/
public class ClassDeserializationValidator implements DeserializationValidator
{
public class ClassDeserializationValidator implements DeserializationValidator {
//--------------------------------------------------------------------------
//
// Public Static Constants
Expand All @@ -43,25 +38,36 @@ public class ClassDeserializationValidator implements DeserializationValidator
public static final String PROPERTY_DISALLOW_CLASSES = "disallow-classes";
public static final String PROPERTY_CLASS_ATTR = "class";
public static final String PROPERTY_NAME_ATTR = "name";

private static final String [] DEFAULT_ALLOW_CLASSES = {
"flex.messaging.*",
"flex.data.*",
"java.lang.Boolean",
"java.lang.Byte",
"java.lang.Character",
"java.lang.Double",
"java.lang.Float",
"java.lang.Integer",
"java.lang.Long",
"java.lang.Object",
"java.lang.Short",
"java.lang.String",
"java.io.Externalizable",
"java.util.*",
"org.w3c.dom.Document",
"\\[B",
"\\[Ljava.lang.Object;"

private static final String[] DEFAULT_ALLOW_CLASSES = {
"flex.messaging.io.amf.SerializedObject",
"flex.messaging.io.ArrayCollection",
"flex.messaging.io.ObjectProxy",
"flex.messaging.io.SerializationProxy",
"flex.messaging.messages.AcknowledgeMessageExt",
"flex.messaging.messages.AsyncMessageExt",
"flex.messaging.messages.CommandMessageExt",
"flex.data.messages.DataMessageExt",
"flex.data.messages.ManagedRemotingMessageExt",
"flex.data.messages.PagedMessageExt",
"flex.data.messages.SequencedMessageExt",
"flex.data.messages.UpdateCollectionMessageExt",
"flex.data.ChangedItems",
"java.lang.Boolean",
"java.lang.Byte",
"java.lang.Character",
"java.lang.Double",
"java.lang.Float",
"java.lang.Integer",
"java.lang.Long",
"java.lang.Object",
"java.lang.Short",
"java.lang.String",
"java.io.Externalizable",
"java.util.Date",
"org.w3c.dom.Document",
"\\[B",
"\\[Ljava.lang.Object;"
};

//--------------------------------------------------------------------------
Expand All @@ -87,6 +93,10 @@ public class ClassDeserializationValidator implements DeserializationValidator
private Map<String, Pattern> allowClassPatterns;
private Map<String, Pattern> disallowClassPatterns;

public ClassDeserializationValidator() {
}


//--------------------------------------------------------------------------
//
// Public Methods
Expand All @@ -98,10 +108,8 @@ public class ClassDeserializationValidator implements DeserializationValidator
*
* @param classNamePattern The name of the class which can be a regular expression.
*/
public void addAllowClassPattern(String classNamePattern)
{
synchronized (lock)
{
public void addAllowClassPattern(String classNamePattern) {
synchronized (lock) {
if (allowClassPatterns == null)
allowClassPatterns = new HashMap<String, Pattern>();

Expand All @@ -116,10 +124,8 @@ public void addAllowClassPattern(String classNamePattern)
*
* @param classNamePattern The name of the class which can be a regular expression.
*/
public void removeAllowClassPattern(String classNamePattern)
{
synchronized (lock)
{
public void removeAllowClassPattern(String classNamePattern) {
synchronized (lock) {
if (allowClassPatterns != null)
allowClassPatterns.remove(classNamePattern);

Expand All @@ -132,10 +138,8 @@ public void removeAllowClassPattern(String classNamePattern)
*
* @param classNamePattern The name of the class which can be a regular expression.
*/
public void addDisallowClassPattern(String classNamePattern)
{
synchronized (lock)
{
public void addDisallowClassPattern(String classNamePattern) {
synchronized (lock) {
if (disallowClassPatterns == null)
disallowClassPatterns = new HashMap<String, Pattern>();

Expand All @@ -150,10 +154,8 @@ public void addDisallowClassPattern(String classNamePattern)
*
* @param classNamePattern The name of the class which can be a regular expression.
*/
public void removeDisallowClassPattern(String classNamePattern)
{
synchronized (lock)
{
public void removeDisallowClassPattern(String classNamePattern) {
synchronized (lock) {
if (disallowClassPatterns != null)
disallowClassPatterns.remove(classNamePattern);

Expand All @@ -167,12 +169,11 @@ public void removeDisallowClassPattern(String classNamePattern)
* therefore this method always returns true.
*
* @param instance The Array or List instance.
* @param index The index at which the value is being assigned.
* @param value The value that is assigned to the index.
* @param index The index at which the value is being assigned.
* @param value The value that is assigned to the index.
* @return True.
*/
public boolean validateAssignment(Object instance, int index, Object value)
{
public boolean validateAssignment(Object instance, int index, Object value) {
return true;
}

Expand All @@ -181,13 +182,12 @@ public boolean validateAssignment(Object instance, int index, Object value)
* to a value but this class only deals with class creations, therefore this
* method always returns true.
*
* @param instance The instance with the property that is being assigned a new value.
* @param instance The instance with the property that is being assigned a new value.
* @param propertyName The name of the property that is being assigned.
* @param value The value that the property is being assigned to.
* @param value The value that the property is being assigned to.
* @return True.
*/
public boolean validateAssignment(Object instance, String propertyName, Object value)
{
public boolean validateAssignment(Object instance, String propertyName, Object value) {
return true;
}

Expand All @@ -199,9 +199,8 @@ public boolean validateAssignment(Object instance, String propertyName, Object v
* @param c The class that is being created.
* @return True if the creation is valid.
*/
public boolean validateCreation(Class<?> c)
{
String className = c == null? null : c.getName();
public boolean validateCreation(Class<?> c) {
String className = c == null ? null : c.getName();
if (className == null)
return true;

Expand All @@ -217,25 +216,19 @@ public boolean validateCreation(Class<?> c)
// go through the disallow and allow class patterns list.

// Disallow the class if there's a disallow-classes list, and the class is in that list.
if (disallowClassPatterns != null && !disallowClassPatterns.isEmpty())
{
for (Pattern pattern : disallowClassPatterns.values())
{
if (pattern.matcher(className).matches())
{
if (disallowClassPatterns != null && !disallowClassPatterns.isEmpty()) {
for (Pattern pattern : disallowClassPatterns.values()) {
if (pattern.matcher(className).matches()) {
addDisallowClass(className);
return false;
}
}
}

// Disallow the class if there's an allowed-classes list, and the class is NOT in that list.
if (allowClassPatterns != null && !allowClassPatterns.isEmpty())
{
for (Pattern pattern : allowClassPatterns.values())
{
if (pattern.matcher(className).matches())
{
if (allowClassPatterns != null && !allowClassPatterns.isEmpty()) {
for (Pattern pattern : allowClassPatterns.values()) {
if (pattern.matcher(className).matches()) {
addAllowClass(className);
return true;
}
Expand All @@ -250,43 +243,37 @@ public boolean validateCreation(Class<?> c)
return true;
}

/** {@inheritDoc} */
public void initialize(String id, ConfigMap properties)
{
/**
* {@inheritDoc}
*/
public void initialize(String id, ConfigMap properties) {
// Apply default allow classes
for (String defaultAllowClassPattern : DEFAULT_ALLOW_CLASSES)
{
for (String defaultAllowClassPattern : DEFAULT_ALLOW_CLASSES) {
addAllowClassPattern(defaultAllowClassPattern);
}

if (properties == null || properties.size() == 0)
return;

// Process allow-classes.
ConfigMap allowedClassesMap = properties.getPropertyAsMap(PROPERTY_ALLOW_CLASSES, null);
if (allowedClassesMap != null && !allowedClassesMap.isEmpty())
{
if (allowedClassesMap != null && !allowedClassesMap.isEmpty()) {
List<?> names = allowedClassesMap.getPropertyAsList(PROPERTY_CLASS_ATTR, null);
if (names != null && !names.isEmpty())
{
for (Object element : names)
{
String name = ((ConfigMap)element).getProperty(PROPERTY_NAME_ATTR);
if (names != null && !names.isEmpty()) {
for (Object element : names) {
String name = ((ConfigMap) element).getProperty(PROPERTY_NAME_ATTR);
addAllowClassPattern(name);
}
}
}

// Process disallow-classes.
ConfigMap disallowedClassesMap = properties.getPropertyAsMap(PROPERTY_DISALLOW_CLASSES, null);
if (disallowedClassesMap != null && !disallowedClassesMap.isEmpty())
{
if (disallowedClassesMap != null && !disallowedClassesMap.isEmpty()) {
List<?> names = disallowedClassesMap.getPropertyAsList(PROPERTY_CLASS_ATTR, null);
if (names != null && !names.isEmpty())
{
for (Object element : names)
{
String name = ((ConfigMap)element).getProperty(PROPERTY_NAME_ATTR);
if (names != null && !names.isEmpty()) {
for (Object element : names) {
String name = ((ConfigMap) element).getProperty(PROPERTY_NAME_ATTR);
addDisallowClassPattern(name);
}
}
Expand All @@ -299,10 +286,8 @@ public void initialize(String id, ConfigMap properties)
//
//--------------------------------------------------------------------------

protected void addAllowClass(String className)
{
synchronized (lock)
{
protected void addAllowClass(String className) {
synchronized (lock) {
if (allowClasses == null)
allowClasses = new HashSet<String>();

Expand All @@ -311,26 +296,21 @@ protected void addAllowClass(String className)
}
}

protected void addDisallowClass(String className)
{
synchronized (lock)
{
protected void addDisallowClass(String className) {
synchronized (lock) {
if (disallowClasses == null)
disallowClasses = new HashSet<String>();

if (!disallowClasses.contains(className))
disallowClasses.add(className);
}
}

protected void clearClassCache()
{
if (allowClasses != null)
{

protected void clearClassCache() {
if (allowClasses != null) {
allowClasses.clear();
}
if (disallowClasses != null)
{
if (disallowClasses != null) {
disallowClasses.clear();
}
}
Expand Down
Loading

0 comments on commit f861f09

Please sign in to comment.