Improve URI/query strings sanitization

This commit is contained in:
Сергей Цыпанов 2020-11-02 12:49:00 +02:00 committed by Juergen Hoeller
parent b077e4cd85
commit 0015fd6734
6 changed files with 47 additions and 30 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 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.
@ -83,7 +83,7 @@ public abstract class NamedParameterUtils {
Assert.notNull(sql, "SQL must not be null");
Set<String> namedParameters = new HashSet<>();
String sqlToUse = sql;
StringBuilder sqlToUse = new StringBuilder(sql);
List<ParameterHolder> parameterList = new ArrayList<>();
char[] statement = sql.toCharArray();
@ -155,7 +155,7 @@ public abstract class NamedParameterUtils {
int j = i + 1;
if (j < statement.length && statement[j] == ':') {
// escaped ":" should be skipped
sqlToUse = sqlToUse.substring(0, i - escapes) + sqlToUse.substring(i - escapes + 1);
sqlToUse.deleteCharAt(i - escapes);
escapes++;
i = i + 2;
continue;
@ -174,7 +174,7 @@ public abstract class NamedParameterUtils {
}
i++;
}
ParsedSql parsedSql = new ParsedSql(sqlToUse);
ParsedSql parsedSql = new ParsedSql(sqlToUse.toString());
for (ParameterHolder ph : parameterList) {
parsedSql.addNamedParameter(ph.getParameterName(), ph.getStartIndex(), ph.getEndIndex());
}

View File

@ -95,7 +95,7 @@ abstract class NamedParameterUtils {
Assert.notNull(sql, "SQL must not be null");
Set<String> namedParameters = new HashSet<>();
String sqlToUse = sql;
StringBuilder sqlToUse = new StringBuilder(sql);
List<ParameterHolder> parameterList = new ArrayList<>();
char[] statement = sql.toCharArray();
@ -171,8 +171,7 @@ abstract class NamedParameterUtils {
int j = i + 1;
if (j < statement.length && statement[j] == ':') {
// escaped ":" should be skipped
sqlToUse = sqlToUse.substring(0, i - escapes)
+ sqlToUse.substring(i - escapes + 1);
sqlToUse.deleteCharAt(i - escapes);
escapes++;
i = i + 2;
continue;
@ -181,7 +180,7 @@ abstract class NamedParameterUtils {
}
i++;
}
ParsedSql parsedSql = new ParsedSql(sqlToUse);
ParsedSql parsedSql = new ParsedSql(sqlToUse.toString());
for (ParameterHolder ph : parameterList) {
parsedSql.addNamedParameter(ph.getParameterName(), ph.getStartIndex(), ph.getEndIndex());
}

View File

@ -1023,15 +1023,21 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable {
if (this.path.length() == 0) {
return null;
}
String path = this.path.toString();
while (true) {
int index = path.indexOf("//");
if (index == -1) {
break;
String sanitized = getSanitizedPath(this.path);
return new HierarchicalUriComponents.FullPathComponent(sanitized);
}
private static String getSanitizedPath(final StringBuilder path) {
int index = path.indexOf("//");
if (index >= 0) {
StringBuilder sanitized = new StringBuilder(path);
while (index != -1) {
sanitized.deleteCharAt(index);
index = sanitized.indexOf("//", index);
}
path = path.substring(0, index) + path.substring(index + 1);
return sanitized.toString();
}
return new HierarchicalUriComponents.FullPathComponent(path);
return path.toString();
}
public void removeTrailingSlash() {

View File

@ -401,18 +401,17 @@ public class UrlPathHelper {
* <li>replace all "//" by "/"</li>
* </ul>
*/
private String getSanitizedPath(final String path) {
String sanitized = path;
while (true) {
int index = sanitized.indexOf("//");
if (index < 0) {
break;
}
else {
sanitized = sanitized.substring(0, index) + sanitized.substring(index + 1);
private static String getSanitizedPath(final String path) {
int index = path.indexOf("//");
if (index >= 0) {
StringBuilder sanitized = new StringBuilder(path);
while (index != -1) {
sanitized.deleteCharAt(index);
index = sanitized.indexOf("//", index);
}
return sanitized.toString();
}
return sanitized;
return path;
}
/**
@ -612,15 +611,20 @@ public class UrlPathHelper {
removeSemicolonContentInternal(requestUri) : removeJsessionid(requestUri));
}
private String removeSemicolonContentInternal(String requestUri) {
private static String removeSemicolonContentInternal(String requestUri) {
int semicolonIndex = requestUri.indexOf(';');
if (semicolonIndex == -1) {
return requestUri;
}
StringBuilder sb = new StringBuilder(requestUri);
while (semicolonIndex != -1) {
int slashIndex = requestUri.indexOf('/', semicolonIndex);
String start = requestUri.substring(0, semicolonIndex);
requestUri = (slashIndex != -1) ? start + requestUri.substring(slashIndex) : start;
semicolonIndex = requestUri.indexOf(';', semicolonIndex);
if (slashIndex >= 0) {
sb.delete(semicolonIndex, slashIndex);
}
semicolonIndex = sb.indexOf(";", semicolonIndex);
}
return requestUri;
return sb.toString();
}
private String removeJsessionid(String requestUri) {

View File

@ -1200,4 +1200,9 @@ class UriComponentsBuilderTests {
assertThat(UriComponentsBuilder.fromUriString("/path?q={asa}asa").toUriString()).isEqualTo("/path?q=%7Basa%7Dasa");
}
@Test
void verifyDoubleSlashReplacedWithSingleOne() {
String path = UriComponentsBuilder.fromPath("/home/").path("/path").build().getPath();
assertThat(path).isEqualTo("/home/path");
}
}

View File

@ -104,6 +104,9 @@ public class UrlPathHelperTests {
request.setRequestURI("/foo+bar");
assertThat(helper.getRequestUri(request)).isEqualTo("/foo+bar");
request.setRequestURI("/home/" + "/path");
assertThat(helper.getRequestUri(request)).isEqualTo("/home/path");
}
@Test