From 13356a7ee2240f740737c5c83bdccdacc30603ab Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 27 Mar 2018 01:00:42 +0200 Subject: [PATCH] Consistent encoded path evaluation in reactive ResourceWebHandler and co Issue: SPR-16616 --- .../resource/PathResourceResolver.java | 23 ++++---- .../reactive/resource/ResourceWebHandler.java | 56 ++++++++++--------- 2 files changed, 42 insertions(+), 37 deletions(-) diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/resource/PathResourceResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/resource/PathResourceResolver.java index 5fa5a20692a..37bcff4b234 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/resource/PathResourceResolver.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/resource/PathResourceResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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. @@ -17,6 +17,7 @@ package org.springframework.web.reactive.resource; import java.io.IOException; +import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.Arrays; import java.util.List; @@ -184,21 +185,21 @@ public class PathResourceResolver extends AbstractResourceResolver { return true; } locationPath = (locationPath.endsWith("/") || locationPath.isEmpty() ? locationPath : locationPath + "/"); - if (!resourcePath.startsWith(locationPath)) { - return false; - } + return (resourcePath.startsWith(locationPath) && !isInvalidEncodedPath(resourcePath)); + } + private boolean isInvalidEncodedPath(String resourcePath) { if (resourcePath.contains("%")) { // Use URLDecoder (vs UriUtils) to preserve potentially decoded UTF-8 chars... - if (URLDecoder.decode(resourcePath, "UTF-8").contains("../")) { - if (logger.isTraceEnabled()) { - logger.trace("Resolved resource path contains \"../\" after decoding: " + resourcePath); - } - return false; + try { + String decodedPath = URLDecoder.decode(resourcePath, "UTF-8"); + return (decodedPath.contains("../") || decodedPath.contains("..\\")); + } + catch (UnsupportedEncodingException ex) { + // Should never happen... } } - - return true; + return false; } } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/resource/ResourceWebHandler.java b/spring-webflux/src/main/java/org/springframework/web/reactive/resource/ResourceWebHandler.java index 215a50f6c8d..1d1782a392c 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/resource/ResourceWebHandler.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/resource/ResourceWebHandler.java @@ -28,7 +28,6 @@ import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import reactor.core.Exceptions; import reactor.core.publisher.Mono; import org.springframework.beans.factory.InitializingBean; @@ -314,9 +313,9 @@ public class ResourceWebHandler implements WebHandler, InitializingBean { } protected Mono getResource(ServerWebExchange exchange) { - String name = HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE; PathContainer pathWithinHandler = exchange.getRequiredAttribute(name); + String path = processPath(pathWithinHandler.value()); if (!StringUtils.hasText(path) || isInvalidPath(path)) { if (logger.isTraceEnabled()) { @@ -324,31 +323,11 @@ public class ResourceWebHandler implements WebHandler, InitializingBean { } return Mono.empty(); } - - if (path.contains("%")) { - try { - // Use URLDecoder (vs UriUtils) to preserve potentially decoded UTF-8 chars - String decodedPath = URLDecoder.decode(path, "UTF-8"); - if (isInvalidPath(decodedPath)) { - if (logger.isTraceEnabled()) { - logger.trace("Ignoring invalid resource path with escape sequences [" + path + "]."); - } - return Mono.empty(); - } - decodedPath = processPath(decodedPath); - if (isInvalidPath(decodedPath)) { - if (logger.isTraceEnabled()) { - logger.trace("Ignoring invalid resource path with escape sequences [" + path + "]."); - } - return Mono.empty(); - } - } - catch (IllegalArgumentException ex) { - // ignore - } - catch (UnsupportedEncodingException ex) { - return Mono.error(Exceptions.propagate(ex)); + if (isInvalidEncodedPath(path)) { + if (logger.isTraceEnabled()) { + logger.trace("Ignoring invalid resource path with escape sequences [" + path + "]"); } + return Mono.empty(); } ResourceResolverChain resolveChain = createResolverChain(); @@ -420,6 +399,31 @@ public class ResourceWebHandler implements WebHandler, InitializingBean { return (slash ? "/" : ""); } + /** + * Check whether the given path contains invalid escape sequences. + * @param path the path to validate + * @return {@code true} if the path is invalid, {@code false} otherwise + */ + private boolean isInvalidEncodedPath(String path) { + if (path.contains("%")) { + try { + // Use URLDecoder (vs UriUtils) to preserve potentially decoded UTF-8 chars + String decodedPath = URLDecoder.decode(path, "UTF-8"); + if (isInvalidPath(decodedPath)) { + return true; + } + decodedPath = processPath(decodedPath); + if (isInvalidPath(decodedPath)) { + return true; + } + } + catch (IllegalArgumentException | UnsupportedEncodingException ex) { + // Should never happen... + } + } + return false; + } + /** * Identifies invalid resource paths. By default rejects: *