Skip to content

Commit

Permalink
Merge pull request #2079 from harawata/desrialization-warning
Browse files Browse the repository at this point in the history
Output warning when deserializing object stream
  • Loading branch information
harawata committed Oct 6, 2020
2 parents 6c6756c + 9caf480 commit d89b300
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 33 deletions.
Expand Up @@ -27,6 +27,7 @@
import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.cache.CacheException;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.io.SerialFilterChecker;

/**
* @author Clinton Begin
Expand Down Expand Up @@ -96,6 +97,7 @@ private byte[] serialize(Serializable value) {
}

private Serializable deserialize(byte[] value) {
SerialFilterChecker.check();
Serializable result;
try (ByteArrayInputStream bis = new ByteArrayInputStream(value);
ObjectInputStream ois = new CustomObjectInputStream(bis)) {
Expand Down
@@ -1,5 +1,5 @@
/**
* Copyright 2009-2019 the original author or authors.
* Copyright 2009-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -19,20 +19,19 @@
import java.io.ByteArrayOutputStream;
import java.io.Externalizable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InvalidClassException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.io.ObjectStreamException;
import java.io.StreamCorruptedException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.io.SerialFilterChecker;
import org.apache.ibatis.reflection.factory.ObjectFactory;

/**
Expand Down Expand Up @@ -108,8 +107,10 @@ protected final Object readResolve() throws ObjectStreamException {
return this.userBean;
}

SerialFilterChecker.check();

/* First run */
try (ObjectInputStream in = new LookAheadObjectInputStream(new ByteArrayInputStream(this.userBeanBytes))) {
try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(this.userBeanBytes))) {
this.userBean = in.readObject();
this.unloadedProperties = (Map<String, ResultLoaderMap.LoadPair>) in.readObject();
this.objectFactory = (ObjectFactory) in.readObject();
Expand All @@ -130,33 +131,4 @@ protected final Object readResolve() throws ObjectStreamException {

protected abstract Object createDeserializationProxy(Object target, Map<String, ResultLoaderMap.LoadPair> unloadedProperties, ObjectFactory objectFactory,
List<Class<?>> constructorArgTypes, List<Object> constructorArgs);

private static class LookAheadObjectInputStream extends ObjectInputStream {
private static final List<String> blacklist = Arrays.asList(
"org.apache.commons.beanutils.BeanComparator",
"org.apache.commons.collections.functors.InvokerTransformer",
"org.apache.commons.collections.functors.InstantiateTransformer",
"org.apache.commons.collections4.functors.InvokerTransformer",
"org.apache.commons.collections4.functors.InstantiateTransformer",
"org.codehaus.groovy.runtime.ConvertedClosure",
"org.codehaus.groovy.runtime.MethodClosure",
"org.springframework.beans.factory.ObjectFactory",
"org.springframework.transaction.jta.JtaTransactionManager",
"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");

public LookAheadObjectInputStream(InputStream in) throws IOException {
super(in);
}

@Override
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
String className = desc.getName();
if (blacklist.contains(className)) {
throw new InvalidClassException(className, "Deserialization is not allowed for security reasons. "
+ "It is strongly recommended to configure the deserialization filter provided by JDK. "
+ "See http://openjdk.java.net/jeps/290 for the details.");
}
return super.resolveClass(desc);
}
}
}
54 changes: 54 additions & 0 deletions src/main/java/org/apache/ibatis/io/SerialFilterChecker.java
@@ -0,0 +1,54 @@
/**
* Copyright 2009-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.ibatis.io;

import java.security.Security;

import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;

public final class SerialFilterChecker {
private static final Log log = LogFactory.getLog(SerialFilterChecker.class);
/* Property key for the JEP-290 serialization filters */
private static final String JDK_SERIAL_FILTER = "jdk.serialFilter";
private static final boolean SERIAL_FILTER_MISSING;
private static boolean firstInvocation = true;

static {
Object serialFilter;
try {
Class<?> objectFilterConfig = Class.forName("java.io.ObjectInputFilter$Config");
serialFilter = objectFilterConfig.getMethod("getSerialFilter").invoke(null);
} catch (ReflectiveOperationException e) {
// Java 1.8
serialFilter = System.getProperty(JDK_SERIAL_FILTER, Security.getProperty(JDK_SERIAL_FILTER));
}
SERIAL_FILTER_MISSING = serialFilter == null;
}

public static void check() {
if (firstInvocation && SERIAL_FILTER_MISSING) {
firstInvocation = false;
log.warn(
"As you are using functionality that deserializes object streams, it is recommended to define the JEP-290 serial filter. "
+ "Please refer to https://docs.oracle.com/pls/topic/lookup?ctx=javase15&id=GUID-8296D8E8-2B93-4B9A-856E-0A65AF9B8C66");
}
}

private SerialFilterChecker() {
}
}

0 comments on commit d89b300

Please sign in to comment.