diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/ResourceServlet.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/ResourceServlet.java index 446c2bf1fc..d0a3ba7921 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/ResourceServlet.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/ResourceServlet.java @@ -270,18 +270,18 @@ public class ResourceServlet extends HttpServletBean { if (this.contentType != null) { response.setContentType(this.contentType); } - String[] resourceUrls = StringUtils.tokenizeToStringArray(resourceUrl, RESOURCE_URL_DELIMITERS); for (String url : resourceUrls) { + String path = StringUtils.cleanPath(url); // Check whether URL matches allowed resources - if (this.allowedResources != null && !this.pathMatcher.match(this.allowedResources, url)) { - throw new ServletException("Resource [" + url + + if (this.allowedResources != null && !this.pathMatcher.match(this.allowedResources, path)) { + throw new ServletException("Resource [" + path + "] does not match allowed pattern [" + this.allowedResources + "]"); } if (logger.isDebugEnabled()) { - logger.debug("Including resource [" + url + "]"); + logger.debug("Including resource [" + path + "]"); } - RequestDispatcher rd = request.getRequestDispatcher(url); + RequestDispatcher rd = request.getRequestDispatcher(path); rd.include(request, response); } } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/ResourceServletTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/ResourceServletTests.java new file mode 100644 index 0000000000..2ba08e26b6 --- /dev/null +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/ResourceServletTests.java @@ -0,0 +1,61 @@ +/* + * Copyright 2002-2016 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.springframework.web.servlet; + +import java.io.IOException; +import javax.servlet.ServletException; + +import org.junit.Test; + +import org.springframework.mock.web.test.MockHttpServletRequest; +import org.springframework.mock.web.test.MockHttpServletResponse; +import org.springframework.mock.web.test.MockServletConfig; + +/** + * @author Rossen Stoyanchev + */ +public class ResourceServletTests { + + @Test(expected = ServletException.class) + public void example1() throws Exception { + testInvalidResourceUrl("/resources/**", "/resources/../WEB-INF/web.xml"); + } + + @Test(expected = ServletException.class) + public void example2() throws Exception { + testInvalidResourceUrl("/resources/*", "/resources/..\\WEB-INF\\web.xml"); + } + + @Test(expected = ServletException.class) + public void example3() throws Exception { + testInvalidResourceUrl("/resources/*", "/resources/..\\Servlet2?param=111"); + } + + private void testInvalidResourceUrl(String allowedResources, String resourceParam) + throws ServletException, IOException { + + ResourceServlet servlet = new ResourceServlet(); + servlet.setAllowedResources(allowedResources); + servlet.init(new MockServletConfig()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/"); + request.addParameter("resource", resourceParam); + MockHttpServletResponse response = new MockHttpServletResponse(); + + servlet.service(request, response); + } + +}