Up-to-date guidelines for serialization-based endpoints

Issue: SPR-15317
This commit is contained in:
Juergen Hoeller
2017-03-24 11:09:57 +01:00
parent b90d3d0e88
commit 2236262fc6
7 changed files with 59 additions and 43 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2017 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.
@@ -43,14 +43,15 @@ import org.springframework.util.Assert;
* @since 1.1
* @see #doExecuteRequest
*/
public abstract class AbstractHttpInvokerRequestExecutor
implements HttpInvokerRequestExecutor, BeanClassLoaderAware {
public abstract class AbstractHttpInvokerRequestExecutor implements HttpInvokerRequestExecutor, BeanClassLoaderAware {
/**
* Default content type: "application/x-java-serialized-object"
*/
public static final String CONTENT_TYPE_SERIALIZED_OBJECT = "application/x-java-serialized-object";
private static final int SERIALIZED_INVOCATION_BYTE_ARRAY_INITIAL_SIZE = 1024;
protected static final String HTTP_METHOD_POST = "POST";
@@ -67,9 +68,6 @@ public abstract class AbstractHttpInvokerRequestExecutor
protected static final String ENCODING_GZIP = "gzip";
private static final int SERIALIZED_INVOCATION_BYTE_ARRAY_INITIAL_SIZE = 1024;
protected final Log logger = LogFactory.getLog(getClass());
private String contentType = CONTENT_TYPE_SERIALIZED_OBJECT;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 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.
@@ -46,14 +46,19 @@ import org.springframework.remoting.support.RemoteInvocationResult;
* a security context). Furthermore, it allows to customize request
* execution via the {@link HttpInvokerRequestExecutor} strategy.
*
* <p>Can use the JDK's {@link java.rmi.server.RMIClassLoader} to load
* classes from a given {@link #setCodebaseUrl codebase}, performing
* on-demand dynamic code download from a remote location. The codebase
* can consist of multiple URLs, separated by spaces. Note that
* RMIClassLoader requires a SecurityManager to be set, analogous to
* when using dynamic class download with standard RMI!
* <p>Can use the JDK's {@link java.rmi.server.RMIClassLoader} to load classes
* from a given {@link #setCodebaseUrl codebase}, performing on-demand dynamic
* code download from a remote location. The codebase can consist of multiple
* URLs, separated by spaces. Note that RMIClassLoader requires a SecurityManager
* to be set, analogous to when using dynamic class download with standard RMI!
* (See the RMI documentation for details.)
*
* <p><b>WARNING: Be aware of vulnerabilities due to unsafe Java deserialization:
* Manipulated input streams could lead to unwanted code execution on the server
* during the deserialization step. As a consequence, do not expose HTTP invoker
* endpoints to untrusted clients but rather just between your own services.</b>
* In general, we strongly recommend any other message format (e.g. JSON) instead.
*
* @author Juergen Hoeller
* @since 1.1
* @see #setServiceUrl

View File

@@ -40,6 +40,7 @@ import org.springframework.beans.factory.FactoryBean;
* Manipulated input streams could lead to unwanted code execution on the server
* during the deserialization step. As a consequence, do not expose HTTP invoker
* endpoints to untrusted clients but rather just between your own services.</b>
* In general, we strongly recommend any other message format (e.g. JSON) instead.
*
* @author Juergen Hoeller
* @since 1.1
@@ -51,8 +52,7 @@ import org.springframework.beans.factory.FactoryBean;
* @see org.springframework.remoting.rmi.RmiProxyFactoryBean
* @see org.springframework.remoting.caucho.HessianProxyFactoryBean
*/
public class HttpInvokerProxyFactoryBean extends HttpInvokerClientInterceptor
implements FactoryBean<Object> {
public class HttpInvokerProxyFactoryBean extends HttpInvokerClientInterceptor implements FactoryBean<Object> {
private Object serviceProxy;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 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.
@@ -52,6 +52,7 @@ import org.springframework.web.util.NestedServletException;
* Manipulated input streams could lead to unwanted code execution on the server
* during the deserialization step. As a consequence, do not expose HTTP invoker
* endpoints to untrusted clients but rather just between your own services.</b>
* In general, we strongly recommend any other message format (e.g. JSON) instead.
*
* @author Juergen Hoeller
* @since 1.1
@@ -60,8 +61,7 @@ import org.springframework.web.util.NestedServletException;
* @see org.springframework.remoting.rmi.RmiServiceExporter
* @see org.springframework.remoting.caucho.HessianServiceExporter
*/
public class HttpInvokerServiceExporter extends RemoteInvocationSerializingExporter
implements HttpRequestHandler {
public class HttpInvokerServiceExporter extends RemoteInvocationSerializingExporter implements HttpRequestHandler {
/**
* Reads a remote invocation from the request, executes it,
@@ -86,10 +86,8 @@ public class HttpInvokerServiceExporter extends RemoteInvocationSerializingExpor
/**
* Read a RemoteInvocation from the given HTTP request.
* <p>Delegates to
* {@link #readRemoteInvocation(javax.servlet.http.HttpServletRequest, java.io.InputStream)}
* with the
* {@link javax.servlet.ServletRequest#getInputStream() servlet request's input stream}.
* <p>Delegates to {@link #readRemoteInvocation(HttpServletRequest, InputStream)} with
* the {@link HttpServletRequest#getInputStream() servlet request's input stream}.
* @param request current HTTP request
* @return the RemoteInvocation object
* @throws IOException in case of I/O failure
@@ -205,12 +203,10 @@ public class HttpInvokerServiceExporter extends RemoteInvocationSerializingExpor
/**
* Decorate an {@code OutputStream} to guard against {@code flush()} calls,
* which are turned into no-ops.
*
* <p>Because {@link ObjectOutputStream#close()} will in fact flush/drain
* the underlying stream twice, this {@link FilterOutputStream} will
* guard against individual flush calls. Multiple flush calls can lead
* to performance issues, since writes aren't gathered as they should be.
*
* @see <a href="https://jira.spring.io/browse/SPR-14040">SPR-14040</a>
*/
private static class FlushGuardedOutputStream extends FilterOutputStream {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 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.
@@ -45,6 +45,12 @@ import org.springframework.remoting.support.RemoteInvocationResult;
* being tied to Java. Nevertheless, it is as easy to set up as Hessian,
* which is its main advantage compared to RMI.
*
* <p><b>WARNING: Be aware of vulnerabilities due to unsafe Java deserialization:
* Manipulated input streams could lead to unwanted code execution on the server
* during the deserialization step. As a consequence, do not expose HTTP invoker
* endpoints to untrusted clients but rather just between your own services.</b>
* In general, we strongly recommend any other message format (e.g. JSON) instead.
*
* @author Juergen Hoeller
* @since 2.5.1
* @see org.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor
@@ -52,15 +58,14 @@ import org.springframework.remoting.support.RemoteInvocationResult;
* @see org.springframework.remoting.caucho.SimpleHessianServiceExporter
*/
@UsesSunHttpServer
public class SimpleHttpInvokerServiceExporter extends RemoteInvocationSerializingExporter
implements HttpHandler {
public class SimpleHttpInvokerServiceExporter extends RemoteInvocationSerializingExporter implements HttpHandler {
/**
* Reads a remote invocation from the request, executes it,
* and writes the remote invocation result to the response.
* @see #readRemoteInvocation(com.sun.net.httpserver.HttpExchange)
* @see #invokeAndCreateResult(org.springframework.remoting.support.RemoteInvocation, Object)
* @see #writeRemoteInvocationResult(com.sun.net.httpserver.HttpExchange, org.springframework.remoting.support.RemoteInvocationResult)
* @see #readRemoteInvocation(HttpExchange)
* @see #invokeAndCreateResult(RemoteInvocation, Object)
* @see #writeRemoteInvocationResult(HttpExchange, RemoteInvocationResult)
*/
@Override
public void handle(HttpExchange exchange) throws IOException {
@@ -78,10 +83,8 @@ public class SimpleHttpInvokerServiceExporter extends RemoteInvocationSerializin
/**
* Read a RemoteInvocation from the given HTTP request.
* <p>Delegates to
* {@link #readRemoteInvocation(com.sun.net.httpserver.HttpExchange, java.io.InputStream)}
* with the
* {@link com.sun.net.httpserver.HttpExchange#getRequestBody()} request's input stream}.
* <p>Delegates to {@link #readRemoteInvocation(HttpExchange, InputStream)}
* with the {@link HttpExchange#getRequestBody()} request's input stream}.
* @param exchange current HTTP request/response
* @return the RemoteInvocation object
* @throws java.io.IOException in case of I/O failure