Skip to content

Commit

Permalink
security: fix some serializer vulnerabilities (#5805)
Browse files Browse the repository at this point in the history
  • Loading branch information
slievrly authored Aug 28, 2023
1 parent e014e5a commit 436d674
Show file tree
Hide file tree
Showing 11 changed files with 258 additions and 247 deletions.
1 change: 1 addition & 0 deletions changes/en-us/2.0.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ The version is updated as follows:
- [[#5642](https://github.com/seata/seata/pull/5642)] add Hessian Serializer WhiteDenyList
- [[#5694](https://github.com/seata/seata/pull/5694)] fix several node.js security vulnerabilities
- [[#5801](https://github.com/seata/seata/pull/5801)] fix some dependencies vulnerability
- [[#5805](https://github.com/seata/seata/pull/5805)] fix some serializer vulnerabilities

### test:
- [[#5308](https://github.com/seata/seata/pull/5308)] add unit test [FileLoader, ObjectHolder, StringUtils]
Expand Down
1 change: 1 addition & 0 deletions changes/zh-cn/2.0.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ Seata 是一款开源的分布式事务解决方案,提供高性能和简单
- [[#5642](https://github.com/seata/seata/pull/5642)] 增加Hessian 序列化黑白名单
- [[#5694](https://github.com/seata/seata/pull/5694)] 修复若干Node.js依赖安全漏洞
- [[#5801](https://github.com/seata/seata/pull/5801)] 修复Java依赖安全漏洞
- [[#5805](https://github.com/seata/seata/pull/5805)] 修复序列化漏洞

### test:
- [[#5308](https://github.com/seata/seata/pull/5308)] 添加单元测试用例 [FileLoader, ObjectHolder, StringUtils]
Expand Down
4 changes: 3 additions & 1 deletion core/src/main/java/io/seata/core/protocol/MergeMessage.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@
*/
package io.seata.core.protocol;

import java.io.Serializable;

/**
* The interface Merge message.
*
* @author slievrly
*/
public interface MergeMessage {
public interface MergeMessage extends Serializable {
}
3 changes: 2 additions & 1 deletion core/src/main/java/io/seata/core/protocol/RpcMessage.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import io.seata.common.util.StringUtils;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

Expand All @@ -25,7 +26,7 @@
*
* @author slievrly
*/
public class RpcMessage {
public class RpcMessage implements Serializable {

private int id;
private byte messageType;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.core.serializer;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;

import io.seata.core.exception.TransactionExceptionCode;
import io.seata.core.model.BranchStatus;
import io.seata.core.model.BranchType;
import io.seata.core.model.GlobalStatus;
import io.seata.core.protocol.ResultCode;

/**
* Serializer Security Registry
* @author funkye
*/
public class SerializerSecurityRegistry {
private static final Set<Class<?>> ALLOW_CLAZZ_SET = new HashSet<>();

private static final Set<String> ALLOW_CLAZZ_PATTERN = new HashSet<>();

private static final Set<String> DENY_CLAZZ_PATTERN = new HashSet<>();

private static final String CLASS_POSTFIX = ".class";

private static final String ABSTRACT_CLASS_ID = "Abstract";

private static final String REQUEST_CLASS_ID = "Request";

private static final String RESPONSE_CLASS_ID = "Response";

private static final String MESSAGE_CLASS_ID = "Message";

static {
ALLOW_CLAZZ_SET.addAll(Arrays.asList(getBasicClassType()));
ALLOW_CLAZZ_SET.addAll(Arrays.asList(getCollectionClassType()));
ALLOW_CLAZZ_SET.addAll(getProtocolType());
ALLOW_CLAZZ_SET.addAll(Arrays.asList(getProtocolInnerFields()));

for (Class<?> clazz : ALLOW_CLAZZ_SET) {
ALLOW_CLAZZ_PATTERN.add(clazz.getCanonicalName());
}
ALLOW_CLAZZ_PATTERN.add(getSeataClassPattern());

DENY_CLAZZ_PATTERN.addAll(Arrays.asList(getDenyClassPatternList()));
}

public static Set<Class<?>> getAllowClassType() {
return Collections.unmodifiableSet(ALLOW_CLAZZ_SET);
}

public static Set<String> getAllowClassPattern() {
return Collections.unmodifiableSet(ALLOW_CLAZZ_PATTERN);
}

public static Set<String> getDenyClassPattern() {
return Collections.unmodifiableSet(DENY_CLAZZ_PATTERN);
}

private static Class<?>[] getBasicClassType() {
return new Class[] {Boolean.class, Byte.class, Character.class, Double.class, Float.class, Integer.class,
Long.class, Short.class, Number.class, Class.class, String.class};
}

private static Class<?>[] getCollectionClassType() {
return new Class[] {ArrayList.class, LinkedList.class, HashSet.class,
LinkedHashSet.class, TreeSet.class, HashMap.class, LinkedHashMap.class, TreeMap.class};
}

private static String getSeataClassPattern() {
return "io.seata.*";
}

private static String[] getDenyClassPatternList() {
return new String[] {"javax.naming.InitialContext", "javax.net.ssl.*", "com.unboundid.ldap.*"};
}

private static Set<Class<?>> getProtocolType() {
Enumeration<URL> packageDir = null;
String packageName = "io.seata.core.protocol";
Set<Class<?>> classNameSet = new HashSet<>();
try {
packageDir = Thread.currentThread().getContextClassLoader().getResources(packageName.replace(".", "/"));
} catch (IOException ignore) {
}
while (packageDir.hasMoreElements()) {
String filePath = packageDir.nextElement().getFile();
findProtocolClassByPackage(filePath, packageName, classNameSet);
}
return classNameSet;
}

private static void findProtocolClassByPackage(String classPath, String rootPackageName, Set classNameSet) {
File file = new File(classPath);
if (!file.exists()) {
return;
}
if (file.isDirectory()) {
File[] files = file.listFiles();
if (null == files) {
return;
}
for (File path : files) {
if (path.isDirectory()) {
findProtocolClassByPackage(path.getAbsolutePath(), rootPackageName + "." + path.getName(),
classNameSet);
} else {
findProtocolClassByPackage(path.getAbsolutePath(), rootPackageName, classNameSet);
}
}
} else {
if (matchProtocol(file.getName())) {
String className = file.getName().substring(0, file.getName().length() - CLASS_POSTFIX.length());
try {
classNameSet.add(
Thread.currentThread().getContextClassLoader().loadClass(rootPackageName + '.' + className));
} catch (ClassNotFoundException ignore) {
//ignore interface
}
}
}
}

private static boolean matchProtocol(String fileName) {
if (!fileName.endsWith(CLASS_POSTFIX)) {
return false;
}
fileName = fileName.replace(CLASS_POSTFIX, "");
if (fileName.startsWith(ABSTRACT_CLASS_ID)) {
return false;
}
if (fileName.contains(REQUEST_CLASS_ID) || fileName.contains(RESPONSE_CLASS_ID) || fileName.endsWith(MESSAGE_CLASS_ID)) {
return true;
}
return false;
}

private static Class<?>[] getProtocolInnerFields() {
return new Class<?>[] {ResultCode.class, GlobalStatus.class, BranchStatus.class, BranchType.class, TransactionExceptionCode.class};
}
}
Loading

0 comments on commit 436d674

Please sign in to comment.