Thursday, April 28, 2011

XSS - prevent path manipulation

Few days ago I have been asked by a customer to add validation for file download functionality.

They needed to verify that the file requested from web page is in working directory or in some of its sub directories and log once it isn't. And this is the final code (if you know of some better/existing solution, just let me know):

public static String correctFilePath(String filePath, boolean allowSubDirAccess) {
String newFilePath = filePath;

if (StringUtils.isNotBlank(newFilePath)) {
String normalizedFilePath = new File(newFilePath).getPath();

if (StringUtils.startsWith(normalizedFilePath, File.separator)) {
log.error("attempt to access the root directory: " + filePath);
}

List<String> allowedPathElements = new ArrayList<String>();
for (String pathElement : StringUtils.split(normalizedFilePath, File.separator)) {
pathElement = pathElement.trim();
if (!".".equals(pathElement)) {
if (pathElement.contains(":")) {
log.error("attempt to access the root directory: " + filePath);
} else if ("..".equals(pathElement)) {
if (allowedPathElements.size() > 0) {
allowedPathElements.remove(allowedPathElements.size() - 1);
} else {
log.error("attempt to access parent of working directory: " + filePath);
}
} else {
allowedPathElements.add(pathElement);
}
}
}

if (!allowSubDirAccess) {
if (allowedPathElements.size() > 1) {
log.error("attempt to access files not located in working directory: " + filePath);
}

newFilePath = allowedPathElements.get(allowedPathElements.size() - 1);
} else {

newFilePath = StringUtils.join(allowedPathElements, File.separator);
}
}

return newFilePath;
}