优化本地存储检测安全性的代码

This commit is contained in:
zhaojun
2023-03-05 15:33:29 +08:00
parent 71a4fdfbaf
commit 77b2253ff6

View File

@@ -45,7 +45,7 @@ import java.util.List;
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Slf4j
public class LocalServiceImpl extends AbstractProxyTransferService<LocalParam> {
private static final String PREVIEW_PARAM_NAME = "preview";
@Override
@@ -91,7 +91,7 @@ public class LocalServiceImpl extends AbstractProxyTransferService<LocalParam> {
@Override
public FileItemResult getFileItem(String pathAndName) {
checkPathSecurity(pathAndName);
String fullPath = StringUtils.concat(param.getFilePath(), pathAndName);
File file = new File(fullPath);
@@ -109,7 +109,7 @@ public class LocalServiceImpl extends AbstractProxyTransferService<LocalParam> {
public boolean newFolder(String path, String name) {
checkPathSecurity(path);
checkNameSecurity(name);
String fullPath = StringUtils.concat(param.getFilePath(), path, name);
return FileUtil.mkdir(fullPath) != null;
}
@@ -119,7 +119,7 @@ public class LocalServiceImpl extends AbstractProxyTransferService<LocalParam> {
public boolean deleteFile(String path, String name) {
checkPathSecurity(path);
checkNameSecurity(name);
String fullPath = StringUtils.concat(param.getFilePath(), path, name);
return FileUtil.del(fullPath);
}
@@ -129,7 +129,7 @@ public class LocalServiceImpl extends AbstractProxyTransferService<LocalParam> {
public boolean deleteFolder(String path, String name) {
checkPathSecurity(path);
checkNameSecurity(name);
return deleteFile(path, name);
}
@@ -137,9 +137,8 @@ public class LocalServiceImpl extends AbstractProxyTransferService<LocalParam> {
@Override
public boolean renameFile(String path, String name, String newName) {
checkPathSecurity(path);
checkNameSecurity(name);
checkNameSecurity(newName);
checkNameSecurity(name, newName);
// 如果文件名没变,不做任何操作.
if (StrUtil.equals(name, newName)) {
return true;
@@ -147,12 +146,12 @@ public class LocalServiceImpl extends AbstractProxyTransferService<LocalParam> {
String srcPath = StringUtils.concat(param.getFilePath(), path, name);
File file = new File(srcPath);
boolean srcExists = file.exists();
if (!srcExists) {
throw ExceptionUtil.wrapRuntime(new FileNotFoundException("文件夹不存在."));
}
FileUtil.rename(file, newName, true);
return true;
}
@@ -161,9 +160,8 @@ public class LocalServiceImpl extends AbstractProxyTransferService<LocalParam> {
@Override
public boolean renameFolder(String path, String name, String newName) {
checkPathSecurity(path);
checkNameSecurity(name);
checkNameSecurity(newName);
checkNameSecurity(name, newName);
return renameFile(path, name, newName);
}
@@ -177,7 +175,7 @@ public class LocalServiceImpl extends AbstractProxyTransferService<LocalParam> {
@Override
public void uploadFile(String pathAndName, InputStream inputStream) {
checkPathSecurity(pathAndName);
String baseFilePath = param.getFilePath();
String uploadPath = StringUtils.removeDuplicateSlashes(baseFilePath + ZFileConstant.PATH_SEPARATOR + pathAndName);
// 如果目录不存在则创建
@@ -195,7 +193,7 @@ public class LocalServiceImpl extends AbstractProxyTransferService<LocalParam> {
@Override
public ResponseEntity<Resource> downloadToStream(String pathAndName) {
checkPathSecurity(pathAndName);
File file = new File(StringUtils.removeDuplicateSlashes(param.getFilePath() + ZFileConstant.PATH_SEPARATOR + pathAndName));
if (!file.exists()) {
ByteArrayResource byteArrayResource = new ByteArrayResource("文件不存在或异常,请联系管理员.".getBytes(StandardCharsets.UTF_8));
@@ -206,19 +204,19 @@ public class LocalServiceImpl extends AbstractProxyTransferService<LocalParam> {
HttpServletRequest request = RequestHolder.getRequest();
String type = request.getParameter("type");
MediaType mimeType = MediaType.APPLICATION_OCTET_STREAM;
if (StrUtil.equals(type, PREVIEW_PARAM_NAME)) {
mimeType = MediaTypeFactory.getMediaType(file.getName()).orElse(MediaType.APPLICATION_OCTET_STREAM);
}
HttpHeaders headers = new HttpHeaders();
if (ObjectUtil.equals(mimeType, MediaType.APPLICATION_OCTET_STREAM)) {
String fileName = file.getName();
headers.setContentDispositionFormData("attachment", StringUtils.encodeAllIgnoreSlashes(fileName));
}
return ResponseEntity
.ok()
.headers(headers)
@@ -243,39 +241,43 @@ public class LocalServiceImpl extends AbstractProxyTransferService<LocalParam> {
}
return fileItemResult;
}
/**
* 检查路径合法性:
* - 只有以 . 开头的允许通过,其他的如 ./ ../ 的都是非法获取上层文件夹内容的路径.
*
* @param path
* @param paths
* 文件路径
*
* @throws IllegalArgumentException 文件路径包含非法字符时会抛出此异常
*/
private static void checkPathSecurity(String path) {
// 路径中不能包含 .. 不然可能会获取到上层文件夹的内容
if (StrUtil.containsAny(path, "../", "..\\")) {
throw new IllegalArgumentException("文件路径存在安全隐患: " + path);
private static void checkPathSecurity(String... paths) {
for (String path : paths) {
// 路径中不能包含 .. 不然可能会获取到上层文件夹的内容
if (StrUtil.containsAny(path, "../", "..\\")) {
throw new IllegalArgumentException("文件路径存在安全隐患: " + path);
}
}
}
/**
* 检查路径合法性:
* - 不为空,且不包含 \ / 字符
*
* @param name
* @param names
* 文件路径
*
* @throws IllegalArgumentException 文件名包含非法字符时会抛出此异常
*/
private static void checkNameSecurity(String name) {
// 路径中不能包含 .. 不然可能会获取到上层文件夹的内容
if (StrUtil.containsAny(name, "\\", "/")) {
throw new IllegalArgumentException("文件名存在安全隐患: " + name);
private static void checkNameSecurity(String... names) {
for (String name : names) {
// 路径中不能包含 .. 不然可能会获取到上层文件夹的内容
if (StrUtil.containsAny(name, "\\", "/")) {
throw new IllegalArgumentException("文件名存在安全隐患: " + name);
}
}
}
}