Skip to content

Commit

Permalink
Consistent encoded path evaluation in reactive ResourceWebHandler and co
Browse files Browse the repository at this point in the history
Issue: SPR-16616
  • Loading branch information
jhoeller committed Mar 26, 2018
1 parent e3d0ef6 commit 13356a7
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 37 deletions.
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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;
Expand Down Expand Up @@ -184,21 +185,21 @@ else if (resource instanceof ClassPathResource) {
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;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@

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;
Expand Down Expand Up @@ -314,41 +313,21 @@ public Mono<Void> handle(ServerWebExchange exchange) {
}

protected Mono<Resource> 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()) {
logger.trace("Ignoring invalid resource path [" + path + "]");
}
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();
Expand Down Expand Up @@ -420,6 +399,31 @@ else if (path.charAt(i) > ' ' && path.charAt(i) != 127) {
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:
* <ul>
Expand Down

0 comments on commit 13356a7

Please sign in to comment.