From 271304336cca361ff55dc6d1a355318386f407b7 Mon Sep 17 00:00:00 2001 From: Albumen Kevin Date: Sat, 29 May 2021 15:47:55 +0800 Subject: [PATCH 1/5] Fix Security --- .../com/alibaba/dubbo/common/Constants.java | 9 ++ .../alibaba/dubbo/config/ServiceConfig.java | 2 + .../dubbo/remoting/exchange/Response.java | 13 +++ .../exchange/codec/ExchangeCodec.java | 40 ++++----- .../remoting/transport/AbstractCodec.java | 10 +++ .../remoting/transport/CodecSupport.java | 85 +++++++++++++++++-- .../remoting/codec/ExchangeCodecTest.java | 4 +- dubbo-rpc/dubbo-rpc-api/pom.xml | 5 ++ .../com/alibaba/dubbo/rpc/Invocation.java | 5 ++ .../com/alibaba/dubbo/rpc/RpcInvocation.java | 19 ++++- .../dubbo/rpc/protocol/AbstractInvoker.java | 9 ++ .../dubbo/DecodeableRpcInvocation.java | 13 ++- .../protocol/dubbo/DecodeableRpcResult.java | 15 ++++ .../dubbo/rpc/protocol/dubbo/DubboCodec.java | 36 +++++++- .../rpc/protocol/dubbo/DubboCodecSupport.java | 51 +++++++++++ .../rpc/protocol/dubbo/DubboInvoker.java | 2 +- 16 files changed, 281 insertions(+), 37 deletions(-) create mode 100644 dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboCodecSupport.java diff --git a/dubbo-common/src/main/java/com/alibaba/dubbo/common/Constants.java b/dubbo-common/src/main/java/com/alibaba/dubbo/common/Constants.java index 9365a4d5b55..82bcb77cab3 100644 --- a/dubbo-common/src/main/java/com/alibaba/dubbo/common/Constants.java +++ b/dubbo-common/src/main/java/com/alibaba/dubbo/common/Constants.java @@ -664,4 +664,13 @@ public class Constants { public static final String ENABLE_NATIVE_JAVA_GENERIC_SERIALIZE = "dubbo.security.serialize.generic.native-java-enable"; public static final String SERIALIZE_BLOCKED_LIST_FILE_PATH = "security/serialize.blockedlist"; + + public static final String DEFAULT_VERSION = "0.0.0"; + + public static final String SERIALIZATION_SECURITY_CHECK_KEY = "serialization.security.check"; + + public static final String SERIALIZATION_ID_KEY = "serialization_id"; + + public static final String INVOCATION_KEY = "invocation"; + } diff --git a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ServiceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ServiceConfig.java index 705ef53f0ac..a680324947d 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ServiceConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/ServiceConfig.java @@ -30,6 +30,7 @@ import com.alibaba.dubbo.config.model.ApplicationModel; import com.alibaba.dubbo.config.model.ProviderModel; import com.alibaba.dubbo.config.support.Parameter; +import com.alibaba.dubbo.remoting.transport.CodecSupport; import com.alibaba.dubbo.rpc.Exporter; import com.alibaba.dubbo.rpc.Invoker; import com.alibaba.dubbo.rpc.Protocol; @@ -317,6 +318,7 @@ protected synchronized void doExport() { path = interfaceName; } doExportUrls(); + CodecSupport.addProviderSupportedSerialization(getUniqueServiceName(), getExportedUrls()); ProviderModel providerModel = new ProviderModel(getUniqueServiceName(), this, ref); ApplicationModel.initProviderModel(getUniqueServiceName(), providerModel); } diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/Response.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/Response.java index d01d20d6638..0b4950ac0fb 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/Response.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/Response.java @@ -16,6 +16,9 @@ */ package com.alibaba.dubbo.remoting.exchange; +import java.util.HashMap; +import java.util.Map; + /** * Response */ @@ -92,6 +95,8 @@ public class Response { private Object mResult; + private Map attributes = new HashMap(2); + public Response() { } @@ -164,6 +169,14 @@ public void setErrorMessage(String msg) { mErrorMsg = msg; } + public Object getAttribute(String key) { + return attributes.get(key); + } + + public void setAttribute(String key, Object value) { + attributes.put(key, value); + } + @Override public String toString() { return "Response [id=" + mId + ", version=" + mVersion + ", status=" + mStatus + ", event=" + mEvent diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/codec/ExchangeCodec.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/codec/ExchangeCodec.java index f1e2bb859ae..81127ac97bb 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/codec/ExchangeCodec.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/exchange/codec/ExchangeCodec.java @@ -38,6 +38,7 @@ import com.alibaba.dubbo.remoting.transport.CodecSupport; import com.alibaba.dubbo.remoting.transport.ExceedPayloadLimitException; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @@ -155,9 +156,12 @@ protected Object decodeBody(Channel channel, InputStream is, byte[] header) thro if (status == Response.OK) { Object data; if (res.isHeartbeat()) { - data = decodeHeartbeatData(channel, in); + byte[] eventPayload = CodecSupport.getPayload(is); + data = decodeHeartbeatData(channel, CodecSupport.deserialize(channel.getUrl(), new ByteArrayInputStream(eventPayload), proto), eventPayload); } else if (res.isEvent()) { - data = decodeEventData(channel, in); + byte[] eventPayload = CodecSupport.getPayload(is); + data = decodeEventData(channel, + CodecSupport.deserialize(channel.getUrl(), new ByteArrayInputStream(eventPayload), proto), eventPayload); } else { data = decodeResponseData(channel, in, getRequestData(id)); } @@ -182,9 +186,13 @@ protected Object decodeBody(Channel channel, InputStream is, byte[] header) thro ObjectInput in = CodecSupport.deserialize(channel.getUrl(), is, proto); Object data; if (req.isHeartbeat()) { - data = decodeHeartbeatData(channel, in); + byte[] eventPayload = CodecSupport.getPayload(is); + data = decodeHeartbeatData(channel, + CodecSupport.deserialize(channel.getUrl(), new ByteArrayInputStream(eventPayload), proto), eventPayload); } else if (req.isEvent()) { - data = decodeEventData(channel, in); + byte[] eventPayload = CodecSupport.getPayload(is); + data = decodeEventData(channel, + CodecSupport.deserialize(channel.getUrl(), new ByteArrayInputStream(eventPayload), proto), eventPayload); } else { data = decodeRequestData(channel, in); } @@ -340,15 +348,6 @@ protected Object decodeData(ObjectInput in) throws IOException { return decodeRequestData(in); } - @Deprecated - protected Object decodeHeartbeatData(ObjectInput in) throws IOException { - try { - return in.readObject(); - } catch (ClassNotFoundException e) { - throw new IOException(StringUtils.toString("Read object failed.", e)); - } - } - protected Object decodeRequestData(ObjectInput in) throws IOException { try { return in.readObject(); @@ -392,8 +391,13 @@ protected Object decodeData(Channel channel, ObjectInput in) throws IOException return decodeRequestData(channel, in); } - protected Object decodeEventData(Channel channel, ObjectInput in) throws IOException { + protected Object decodeEventData(Channel channel, ObjectInput in, byte[] eventPayload) throws IOException { try { + int dataLen = eventPayload.length; + int threshold = Integer.parseInt(System.getProperty("deserialization.event.size", "50")); + if (dataLen > threshold) { + throw new IllegalArgumentException("Event data too long, actual size " + dataLen + ", threshold " + threshold + " rejected for security consideration."); + } return in.readObject(); } catch (ClassNotFoundException e) { throw new IOException(StringUtils.toString("Read object failed.", e)); @@ -401,12 +405,8 @@ protected Object decodeEventData(Channel channel, ObjectInput in) throws IOExcep } @Deprecated - protected Object decodeHeartbeatData(Channel channel, ObjectInput in) throws IOException { - try { - return in.readObject(); - } catch (ClassNotFoundException e) { - throw new IOException(StringUtils.toString("Read object failed.", e)); - } + protected Object decodeHeartbeatData(Channel channel, ObjectInput in, byte[] eventPayload) throws IOException { + return decodeEventData(channel, in, eventPayload); } protected Object decodeRequestData(Channel channel, ObjectInput in) throws IOException { diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/transport/AbstractCodec.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/transport/AbstractCodec.java index 76cb8ab5499..01fee212a94 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/transport/AbstractCodec.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/transport/AbstractCodec.java @@ -24,6 +24,8 @@ import com.alibaba.dubbo.common.utils.NetUtils; import com.alibaba.dubbo.remoting.Channel; import com.alibaba.dubbo.remoting.Codec2; +import com.alibaba.dubbo.remoting.exchange.Request; +import com.alibaba.dubbo.remoting.exchange.Response; import java.io.IOException; import java.net.InetSocketAddress; @@ -51,6 +53,14 @@ protected Serialization getSerialization(Channel channel) { return CodecSupport.getSerialization(channel.getUrl()); } + protected Serialization getSerialization(Channel channel, Request req) { + return CodecSupport.getSerialization(channel.getUrl()); + } + + protected Serialization getSerialization(Channel channel, Response res) { + return CodecSupport.getSerialization(channel.getUrl()); + } + protected boolean isClientSide(Channel channel) { String side = (String) channel.getAttribute(Constants.SIDE_KEY); if ("client".equals(side)) { diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/transport/CodecSupport.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/transport/CodecSupport.java index 3262e12ed15..0eb72c366b6 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/transport/CodecSupport.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/transport/CodecSupport.java @@ -24,18 +24,31 @@ import com.alibaba.dubbo.common.logger.LoggerFactory; import com.alibaba.dubbo.common.serialize.ObjectInput; import com.alibaba.dubbo.common.serialize.Serialization; +import com.alibaba.dubbo.common.utils.CollectionUtils; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import static com.alibaba.dubbo.common.Constants.SERIALIZATION_KEY; public class CodecSupport { private static final Logger logger = LoggerFactory.getLogger(CodecSupport.class); private static Map ID_SERIALIZATION_MAP = new HashMap(); private static Map ID_SERIALIZATIONNAME_MAP = new HashMap(); + private static Map SERIALIZATIONNAME_ID_MAP = new HashMap(); + + private static Map> PROVIDER_SUPPORTED_SERIALIZATION = new ConcurrentHashMap>(); + + private static final ThreadLocal TL_BUFFER = new ThreadLocal(); static { Set supportedExtensions = ExtensionLoader.getExtensionLoader(Serialization.class).getSupportedExtensions(); @@ -51,7 +64,9 @@ public class CodecSupport { } ID_SERIALIZATION_MAP.put(idByte, serialization); ID_SERIALIZATIONNAME_MAP.put(idByte, name); + SERIALIZATIONNAME_ID_MAP.put(name, idByte); } + TL_BUFFER.set(new byte[1024]); } private CodecSupport() { @@ -63,18 +78,15 @@ public static Serialization getSerializationById(Byte id) { public static Serialization getSerialization(URL url) { return ExtensionLoader.getExtensionLoader(Serialization.class).getExtension( - url.getParameter(Constants.SERIALIZATION_KEY, Constants.DEFAULT_REMOTING_SERIALIZATION)); + url.getParameter(SERIALIZATION_KEY, Constants.DEFAULT_REMOTING_SERIALIZATION)); } public static Serialization getSerialization(URL url, Byte id) throws IOException { - Serialization serialization = getSerializationById(id); - String serializationName = url.getParameter(Constants.SERIALIZATION_KEY, Constants.DEFAULT_REMOTING_SERIALIZATION); - // Check if "serialization id" passed from network matches the id on this side(only take effect for JDK serialization), for security purpose. - if (serialization == null - || ((id == 3 || id == 7 || id == 4) && !(serializationName.equals(ID_SERIALIZATIONNAME_MAP.get(id))))) { - throw new IOException("Unexpected serialization id:" + id + " received from network, please check if the peer send the right id."); + Serialization result = getSerializationById(id); + if (result == null) { + throw new IOException("Unrecognized serialize type from consumer: " + id); } - return serialization; + return result; } public static ObjectInput deserialize(URL url, InputStream is, byte proto) throws IOException { @@ -82,4 +94,61 @@ public static ObjectInput deserialize(URL url, InputStream is, byte proto) throw return s.deserialize(url, is); } + /** + * Read all payload to byte[] + * + * @param is + * @return + * @throws IOException + */ + public static byte[] getPayload(InputStream is) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] buffer = getBuffer(is.available()); + int len; + while ((len = is.read(buffer)) > -1) { + baos.write(buffer, 0, len); + } + baos.flush(); + return baos.toByteArray(); + } + + private static byte[] getBuffer(int size) { + byte[] bytes = TL_BUFFER.get(); + if (size <= bytes.length) { + return bytes; + } + return new byte[size]; + } + + public static Byte getIDByName(String name) { + return SERIALIZATIONNAME_ID_MAP.get(name); + } + + public static void checkSerialization(String path, String version, Byte id) throws IOException { + Set supportedSerialization = PROVIDER_SUPPORTED_SERIALIZATION.get(path + ":" + version); + if (CollectionUtils.isNotEmpty(supportedSerialization)) { + if (logger.isWarnEnabled()) { + logger.warn("Serialization security check is enabled but cannot work as expected because " + + "there's no matched provider model for path " + path + ", version " + version); + } + } else { + if (!supportedSerialization.contains(id)) { + throw new IOException("Unexpected serialization id:" + id + " received from network, please check if the peer send the right id."); + } + } + } + + public static void addProviderSupportedSerialization(String serviceName, List exportedUrls) { + if (CollectionUtils.isNotEmpty(exportedUrls)) { + Set supportedSerialization = new HashSet(); + for (URL url : exportedUrls) { + String serializationName = url.getParameter(SERIALIZATION_KEY, Constants.DEFAULT_REMOTING_SERIALIZATION); + Byte localId = SERIALIZATIONNAME_ID_MAP.get(serializationName); + supportedSerialization.add(localId); + } + PROVIDER_SUPPORTED_SERIALIZATION.put(serviceName, Collections.unmodifiableSet(supportedSerialization)); + } + } + + } diff --git a/dubbo-remoting/dubbo-remoting-api/src/test/java/com/alibaba/dubbo/remoting/codec/ExchangeCodecTest.java b/dubbo-remoting/dubbo-remoting-api/src/test/java/com/alibaba/dubbo/remoting/codec/ExchangeCodecTest.java index 163c72c8434..a35f8305c3c 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/test/java/com/alibaba/dubbo/remoting/codec/ExchangeCodecTest.java +++ b/dubbo-remoting/dubbo-remoting-api/src/test/java/com/alibaba/dubbo/remoting/codec/ExchangeCodecTest.java @@ -230,12 +230,14 @@ public void test_Decode_Return_Request_Event_Object() throws IOException { Person person = new Person(); byte[] request = getRequestBytes(person, header); + System.setProperty("deserialization.event.size", "100"); Request obj = (Request) decode(request); Assert.assertEquals(person, obj.getData()); Assert.assertEquals(true, obj.isTwoWay()); Assert.assertEquals(true, obj.isEvent()); Assert.assertEquals(Version.getProtocolVersion(), obj.getVersion()); System.out.println(obj); + System.clearProperty("deserialization.event.size"); } @Test @@ -269,7 +271,7 @@ public void test_Decode_Return_Request_Heartbeat_Object() throws IOException { @Test public void test_Decode_Return_Request_Object() throws IOException { //|10011111|20-stats=ok|id=0|length=0 - byte[] header = new byte[]{MAGIC_HIGH, MAGIC_LOW, (byte) 0xe2, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + byte[] header = new byte[]{MAGIC_HIGH, MAGIC_LOW, (byte) 0xc2, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; Person person = new Person(); byte[] request = getRequestBytes(person, header); diff --git a/dubbo-rpc/dubbo-rpc-api/pom.xml b/dubbo-rpc/dubbo-rpc-api/pom.xml index dac691bd8aa..df74757a8d8 100644 --- a/dubbo-rpc/dubbo-rpc-api/pom.xml +++ b/dubbo-rpc/dubbo-rpc-api/pom.xml @@ -39,5 +39,10 @@ dubbo-serialization-api ${project.parent.version} + + com.alibaba + dubbo-remoting-api + ${project.parent.version} + \ No newline at end of file diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/Invocation.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/Invocation.java index e5a022074e2..8c9dcb560ac 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/Invocation.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/Invocation.java @@ -83,4 +83,9 @@ public interface Invocation { */ Invoker getInvoker(); + Object put(Object key, Object value); + + Object get(Object key); + + Map getAttributes(); } \ No newline at end of file diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcInvocation.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcInvocation.java index 1458131ba6e..13314a5c869 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcInvocation.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcInvocation.java @@ -44,6 +44,8 @@ public class RpcInvocation implements Invocation, Serializable { private transient Invoker invoker; + private Map attributes; + public RpcInvocation() { } @@ -204,11 +206,26 @@ public String getAttachment(String key, String defaultValue) { return value; } + @Override + public Object put(Object key, Object value) { + return attributes.put(key, value); + } + + @Override + public Object get(Object key) { + return attributes.get(key); + } + + @Override + public Map getAttributes() { + return attributes; + } + @Override public String toString() { return "RpcInvocation [methodName=" + methodName + ", parameterTypes=" + Arrays.toString(parameterTypes) + ", arguments=" + Arrays.toString(arguments) - + ", attachments=" + attachments + "]"; + + ", attachments=" + attachments + ", attributes=" + attributes + "]"; } } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/protocol/AbstractInvoker.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/protocol/AbstractInvoker.java index 4ab44b7674d..4b02f5fd4a2 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/protocol/AbstractInvoker.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/protocol/AbstractInvoker.java @@ -22,6 +22,7 @@ import com.alibaba.dubbo.common.logger.Logger; import com.alibaba.dubbo.common.logger.LoggerFactory; import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.remoting.transport.CodecSupport; import com.alibaba.dubbo.rpc.Invocation; import com.alibaba.dubbo.rpc.Invoker; import com.alibaba.dubbo.rpc.Result; @@ -37,6 +38,10 @@ import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; +import static com.alibaba.dubbo.common.Constants.DEFAULT_REMOTING_SERIALIZATION; +import static com.alibaba.dubbo.common.Constants.SERIALIZATION_ID_KEY; +import static com.alibaba.dubbo.common.Constants.SERIALIZATION_KEY; + /** * AbstractInvoker. */ @@ -150,6 +155,10 @@ public Result invoke(Invocation inv) throws RpcException { } RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation); + Byte serializationId = CodecSupport.getIDByName(getUrl().getParameter(SERIALIZATION_KEY, DEFAULT_REMOTING_SERIALIZATION)); + if (serializationId != null) { + invocation.put(SERIALIZATION_ID_KEY, serializationId); + } try { return doInvoke(invocation); diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DecodeableRpcInvocation.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DecodeableRpcInvocation.java index 4002f04e3aa..a106dd822da 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DecodeableRpcInvocation.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DecodeableRpcInvocation.java @@ -37,6 +37,8 @@ import java.util.HashMap; import java.util.Map; +import static com.alibaba.dubbo.common.Constants.SERIALIZATION_ID_KEY; +import static com.alibaba.dubbo.common.Constants.SERIALIZATION_SECURITY_CHECK_KEY; import static com.alibaba.dubbo.rpc.protocol.dubbo.CallbackServiceCodec.decodeInvocationArgument; public class DecodeableRpcInvocation extends RpcInvocation implements Codec, Decodeable { @@ -89,16 +91,23 @@ public void encode(Channel channel, OutputStream output, Object message) throws public Object decode(Channel channel, InputStream input) throws IOException { ObjectInput in = CodecSupport.getSerialization(channel.getUrl(), serializationType) .deserialize(channel.getUrl(), input); + this.put(SERIALIZATION_ID_KEY, serializationType); String dubboVersion = in.readUTF(); request.setVersion(dubboVersion); setAttachment(Constants.DUBBO_VERSION_KEY, dubboVersion); - setAttachment(Constants.PATH_KEY, in.readUTF()); - setAttachment(Constants.VERSION_KEY, in.readUTF()); + String path = in.readUTF(); + setAttachment(Constants.PATH_KEY, path); + String version = in.readUTF(); + setAttachment(Constants.VERSION_KEY, version); setMethodName(in.readUTF()); try { + if (Boolean.parseBoolean(System.getProperty(SERIALIZATION_SECURITY_CHECK_KEY, "false"))) { + CodecSupport.checkSerialization(path, version, serializationType); + } + Object[] args; Class[] pts; String desc = in.readUTF(); diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DecodeableRpcResult.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DecodeableRpcResult.java index e43080a9bf8..0d49466f970 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DecodeableRpcResult.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DecodeableRpcResult.java @@ -37,6 +37,9 @@ import java.lang.reflect.Type; import java.util.Map; +import static com.alibaba.dubbo.common.Constants.SERIALIZATION_ID_KEY; +import static com.alibaba.dubbo.common.Constants.SERIALIZATION_SECURITY_CHECK_KEY; + public class DecodeableRpcResult extends RpcResult implements Codec, Decodeable { private static final Logger log = LoggerFactory.getLogger(DecodeableRpcResult.class); @@ -140,6 +143,15 @@ public Object decode(Channel channel, InputStream input) throws IOException { public void decode() throws Exception { if (!hasDecoded && channel != null && inputStream != null) { try { + if (Boolean.parseBoolean(System.getProperty(SERIALIZATION_SECURITY_CHECK_KEY, "false"))) { + Object serializationType_obj = invocation.get(SERIALIZATION_ID_KEY); + if (serializationType_obj != null) { + if (((Byte) serializationType_obj).compareTo(serializationType) != 0) { + throw new IOException("Unexpected serialization id:" + serializationType + " received from network, please check if the peer send the right id."); + } + } + } + decode(channel, inputStream); } catch (Throwable e) { if (log.isWarnEnabled()) { @@ -153,4 +165,7 @@ public void decode() throws Exception { } } + public Invocation getInvocation() { + return invocation; + } } diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboCodec.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboCodec.java index 3c12448895f..35b95d978f9 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboCodec.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboCodec.java @@ -23,6 +23,7 @@ import com.alibaba.dubbo.common.logger.Logger; import com.alibaba.dubbo.common.logger.LoggerFactory; import com.alibaba.dubbo.common.serialize.ObjectOutput; +import com.alibaba.dubbo.common.serialize.Serialization; import com.alibaba.dubbo.common.utils.ReflectUtils; import com.alibaba.dubbo.common.utils.StringUtils; import com.alibaba.dubbo.remoting.Channel; @@ -35,6 +36,7 @@ import com.alibaba.dubbo.rpc.Result; import com.alibaba.dubbo.rpc.RpcInvocation; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @@ -75,9 +77,13 @@ protected Object decodeBody(Channel channel, InputStream is, byte[] header) thro if (status == Response.OK) { Object data; if (res.isHeartbeat()) { - data = decodeHeartbeatData(channel, CodecSupport.deserialize(channel.getUrl(), is, proto)); + byte[] eventPayload = CodecSupport.getPayload(is); + data = decodeHeartbeatData(channel, + CodecSupport.deserialize(channel.getUrl(), new ByteArrayInputStream(eventPayload), proto), eventPayload); } else if (res.isEvent()) { - data = decodeEventData(channel, CodecSupport.deserialize(channel.getUrl(), is, proto)); + byte[] eventPayload = CodecSupport.getPayload(is); + data = decodeEventData(channel, + CodecSupport.deserialize(channel.getUrl(), new ByteArrayInputStream(eventPayload), proto), eventPayload); } else { DecodeableRpcResult result; if (channel.getUrl().getParameter( @@ -116,9 +122,13 @@ protected Object decodeBody(Channel channel, InputStream is, byte[] header) thro try { Object data; if (req.isHeartbeat()) { - data = decodeHeartbeatData(channel, CodecSupport.deserialize(channel.getUrl(), is, proto)); + byte[] eventPayload = CodecSupport.getPayload(is); + data = decodeHeartbeatData(channel, + CodecSupport.deserialize(channel.getUrl(), new ByteArrayInputStream(eventPayload), proto), eventPayload); } else if (req.isEvent()) { - data = decodeEventData(channel, CodecSupport.deserialize(channel.getUrl(), is, proto)); + byte[] eventPayload = CodecSupport.getPayload(is); + data = decodeEventData(channel, + CodecSupport.deserialize(channel.getUrl(), new ByteArrayInputStream(eventPayload), proto), eventPayload); } else { DecodeableRpcInvocation inv; if (channel.getUrl().getParameter( @@ -207,4 +217,22 @@ protected void encodeResponseData(Channel channel, ObjectOutput out, Object data out.writeObject(result.getAttachments()); } } + + @Override + protected Serialization getSerialization(Channel channel, Request req) { + if (!(req.getData() instanceof Invocation)) { + return super.getSerialization(channel, req); + } + return DubboCodecSupport.getRequestSerialization(channel.getUrl(), (Invocation) req.getData()); + } + + @Override + protected Serialization getSerialization(Channel channel, Response res) { + if (!(res.getResult() instanceof DecodeableRpcResult)) { + return super.getSerialization(channel, res); + } + return DubboCodecSupport.getResponseSerialization(channel.getUrl(), (DecodeableRpcResult) res.getResult()); + } + + } diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboCodecSupport.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboCodecSupport.java new file mode 100644 index 00000000000..9fc65b4cf1e --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboCodecSupport.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 com.alibaba.dubbo.rpc.protocol.dubbo; + +import com.alibaba.dubbo.common.Constants; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.extension.ExtensionLoader; +import com.alibaba.dubbo.common.serialize.Serialization; +import com.alibaba.dubbo.remoting.exchange.Response; +import com.alibaba.dubbo.remoting.transport.CodecSupport; +import com.alibaba.dubbo.rpc.Invocation; + +import static com.alibaba.dubbo.common.Constants.SERIALIZATION_ID_KEY; + +public class DubboCodecSupport { + public static Serialization getRequestSerialization(URL url, Invocation invocation) { + Object serializationType_obj = invocation.get(SERIALIZATION_ID_KEY); + if (serializationType_obj != null) { + return CodecSupport.getSerializationById((Byte) serializationType_obj); + } + return ExtensionLoader.getExtensionLoader(Serialization.class).getExtension( + url.getParameter(Constants.SERIALIZATION_KEY, Constants.DEFAULT_REMOTING_SERIALIZATION)); + } + + public static Serialization getResponseSerialization(URL url, DecodeableRpcResult result) { + Invocation invocation = result.getInvocation(); + if (invocation != null) { + Object serializationType_obj = invocation.get(SERIALIZATION_ID_KEY); + if (serializationType_obj != null) { + return CodecSupport.getSerializationById((Byte) serializationType_obj); + } + } + return ExtensionLoader.getExtensionLoader(Serialization.class).getExtension( + url.getParameter(Constants.SERIALIZATION_KEY, Constants.DEFAULT_REMOTING_SERIALIZATION)); + } + +} diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java index 0c6ea37c00d..2bdbd407ea4 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboInvoker.java @@ -60,7 +60,7 @@ public DubboInvoker(Class serviceType, URL url, ExchangeClient[] clients, Set super(serviceType, url, new String[]{Constants.INTERFACE_KEY, Constants.GROUP_KEY, Constants.TOKEN_KEY, Constants.TIMEOUT_KEY}); this.clients = clients; // get version. - this.version = url.getParameter(Constants.VERSION_KEY, "0.0.0"); + this.version = url.getParameter(Constants.VERSION_KEY, Constants.DEFAULT_VERSION); this.invokers = invokers; } From 056b5d557dc5ac85576d09ad08115f06b1ae38c2 Mon Sep 17 00:00:00 2001 From: Albumen Kevin Date: Sat, 29 May 2021 16:04:00 +0800 Subject: [PATCH 2/5] Fix Implement --- .../alibaba/dubbo/rpc/support/MockInvocation.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/dubbo-rpc/dubbo-rpc-api/src/test/java/com/alibaba/dubbo/rpc/support/MockInvocation.java b/dubbo-rpc/dubbo-rpc-api/src/test/java/com/alibaba/dubbo/rpc/support/MockInvocation.java index 4d290918cce..e1bfdfef46b 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/test/java/com/alibaba/dubbo/rpc/support/MockInvocation.java +++ b/dubbo-rpc/dubbo-rpc-api/src/test/java/com/alibaba/dubbo/rpc/support/MockInvocation.java @@ -63,4 +63,18 @@ public String getAttachment(String key, String defaultValue) { return getAttachments().get(key); } + @Override + public Object put(Object key, Object value) { + return null; + } + + @Override + public Object get(Object key) { + return null; + } + + @Override + public Map getAttributes() { + return null; + } } \ No newline at end of file From 6125ba03397c7d634583b46c2aa9b5c24ddda45a Mon Sep 17 00:00:00 2001 From: Albumen Kevin Date: Sat, 29 May 2021 16:07:57 +0800 Subject: [PATCH 3/5] remove unused import --- .../com/alibaba/dubbo/rpc/protocol/dubbo/DubboCodecSupport.java | 1 - 1 file changed, 1 deletion(-) diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboCodecSupport.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboCodecSupport.java index 9fc65b4cf1e..c89ac489e5f 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboCodecSupport.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DubboCodecSupport.java @@ -20,7 +20,6 @@ import com.alibaba.dubbo.common.URL; import com.alibaba.dubbo.common.extension.ExtensionLoader; import com.alibaba.dubbo.common.serialize.Serialization; -import com.alibaba.dubbo.remoting.exchange.Response; import com.alibaba.dubbo.remoting.transport.CodecSupport; import com.alibaba.dubbo.rpc.Invocation; From 668d8d808fa4649a367d65b93b26121d89b5bc80 Mon Sep 17 00:00:00 2001 From: Albumen Kevin Date: Sat, 29 May 2021 16:17:18 +0800 Subject: [PATCH 4/5] fix npe --- .../dubbo/remoting/transport/CodecSupport.java | 13 +------------ .../java/com/alibaba/dubbo/rpc/RpcInvocation.java | 2 +- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/transport/CodecSupport.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/transport/CodecSupport.java index 0eb72c366b6..a72a6770718 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/transport/CodecSupport.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/transport/CodecSupport.java @@ -48,8 +48,6 @@ public class CodecSupport { private static Map> PROVIDER_SUPPORTED_SERIALIZATION = new ConcurrentHashMap>(); - private static final ThreadLocal TL_BUFFER = new ThreadLocal(); - static { Set supportedExtensions = ExtensionLoader.getExtensionLoader(Serialization.class).getSupportedExtensions(); for (String name : supportedExtensions) { @@ -66,7 +64,6 @@ public class CodecSupport { ID_SERIALIZATIONNAME_MAP.put(idByte, name); SERIALIZATIONNAME_ID_MAP.put(name, idByte); } - TL_BUFFER.set(new byte[1024]); } private CodecSupport() { @@ -103,7 +100,7 @@ public static ObjectInput deserialize(URL url, InputStream is, byte proto) throw */ public static byte[] getPayload(InputStream is) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); - byte[] buffer = getBuffer(is.available()); + byte[] buffer = new byte[1024]; int len; while ((len = is.read(buffer)) > -1) { baos.write(buffer, 0, len); @@ -112,14 +109,6 @@ public static byte[] getPayload(InputStream is) throws IOException { return baos.toByteArray(); } - private static byte[] getBuffer(int size) { - byte[] bytes = TL_BUFFER.get(); - if (size <= bytes.length) { - return bytes; - } - return new byte[size]; - } - public static Byte getIDByName(String name) { return SERIALIZATIONNAME_ID_MAP.get(name); } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcInvocation.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcInvocation.java index 13314a5c869..8c9556a0511 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcInvocation.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcInvocation.java @@ -44,7 +44,7 @@ public class RpcInvocation implements Invocation, Serializable { private transient Invoker invoker; - private Map attributes; + private Map attributes = new HashMap(2); public RpcInvocation() { } From f4c902f5f01174f8ba6a9f8cdb42e9223442f9d0 Mon Sep 17 00:00:00 2001 From: Albumen Kevin Date: Sat, 29 May 2021 17:10:44 +0800 Subject: [PATCH 5/5] fix logic --- .../com/alibaba/dubbo/remoting/transport/CodecSupport.java | 5 ++++- .../dubbo/rpc/protocol/dubbo/DecodeableRpcResult.java | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/transport/CodecSupport.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/transport/CodecSupport.java index a72a6770718..f8a241a182c 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/transport/CodecSupport.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/com/alibaba/dubbo/remoting/transport/CodecSupport.java @@ -115,7 +115,10 @@ public static Byte getIDByName(String name) { public static void checkSerialization(String path, String version, Byte id) throws IOException { Set supportedSerialization = PROVIDER_SUPPORTED_SERIALIZATION.get(path + ":" + version); - if (CollectionUtils.isNotEmpty(supportedSerialization)) { + if (Constants.DEFAULT_VERSION.equals(version) && CollectionUtils.isEmpty(supportedSerialization)) { + supportedSerialization = PROVIDER_SUPPORTED_SERIALIZATION.get(path); + } + if (CollectionUtils.isEmpty(supportedSerialization)) { if (logger.isWarnEnabled()) { logger.warn("Serialization security check is enabled but cannot work as expected because " + "there's no matched provider model for path " + path + ", version " + version); diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DecodeableRpcResult.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DecodeableRpcResult.java index 0d49466f970..e24eb37baa7 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DecodeableRpcResult.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/com/alibaba/dubbo/rpc/protocol/dubbo/DecodeableRpcResult.java @@ -143,7 +143,7 @@ public Object decode(Channel channel, InputStream input) throws IOException { public void decode() throws Exception { if (!hasDecoded && channel != null && inputStream != null) { try { - if (Boolean.parseBoolean(System.getProperty(SERIALIZATION_SECURITY_CHECK_KEY, "false"))) { + if (Boolean.parseBoolean(System.getProperty(SERIALIZATION_SECURITY_CHECK_KEY, "false")) && invocation != null) { Object serializationType_obj = invocation.get(SERIALIZATION_ID_KEY); if (serializationType_obj != null) { if (((Byte) serializationType_obj).compareTo(serializationType) != 0) {