mirror of
https://github.com/jeecgboot/JeecgBoot.git
synced 2026-02-02 16:45:24 +08:00
文件目录扫描漏洞
This commit is contained in:
@ -286,5 +286,38 @@ public class SsrfFileTypeFilter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验文件路径安全性,防止路径遍历攻击
|
||||||
|
* @param filePath 文件路径
|
||||||
|
*/
|
||||||
|
public static void checkPathTraversal(String filePath) {
|
||||||
|
if (StringUtils.isBlank(filePath)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 1. 防止路径遍历:不允许 ..
|
||||||
|
if (filePath.contains("..")) {
|
||||||
|
throw new JeecgBootException("文件路径包含非法字符");
|
||||||
|
}
|
||||||
|
// 2. 防止URL编码绕过:%2e = .
|
||||||
|
String fileLower = filePath.toLowerCase();
|
||||||
|
if (fileLower.contains("%2e")) {
|
||||||
|
throw new JeecgBootException("文件路径包含非法字符");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量校验文件路径安全性(逗号分隔的多个文件路径)
|
||||||
|
* @param files 逗号分隔的文件路径
|
||||||
|
*/
|
||||||
|
public static void checkPathTraversalBatch(String files) {
|
||||||
|
if (StringUtils.isBlank(files)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (String file : files.split(",")) {
|
||||||
|
if (StringUtils.isNotBlank(file)) {
|
||||||
|
checkPathTraversal(file.trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.jeecg.ai.handler.LLMHandler;
|
import org.jeecg.ai.handler.LLMHandler;
|
||||||
import org.jeecg.common.exception.JeecgBootException;
|
import org.jeecg.common.exception.JeecgBootException;
|
||||||
import org.jeecg.common.util.AssertUtils;
|
import org.jeecg.common.util.AssertUtils;
|
||||||
|
import org.jeecg.common.util.filter.SsrfFileTypeFilter;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.modules.airag.common.consts.AiragConsts;
|
import org.jeecg.modules.airag.common.consts.AiragConsts;
|
||||||
import org.jeecg.modules.airag.common.handler.AIChatParams;
|
import org.jeecg.modules.airag.common.handler.AIChatParams;
|
||||||
@ -401,6 +402,7 @@ public class AIChatHandler implements IAIChatHandler {
|
|||||||
String filePath = uploadpath + File.separator + imageUrl;
|
String filePath = uploadpath + File.separator + imageUrl;
|
||||||
// 读取文件并转换为 base64 编码字符串
|
// 读取文件并转换为 base64 编码字符串
|
||||||
try {
|
try {
|
||||||
|
SsrfFileTypeFilter.checkPathTraversal(filePath);
|
||||||
Path path = Paths.get(filePath);
|
Path path = Paths.get(filePath);
|
||||||
byte[] fileContent = Files.readAllBytes(path);
|
byte[] fileContent = Files.readAllBytes(path);
|
||||||
String base64Data = Base64.getEncoder().encodeToString(fileContent);
|
String base64Data = Base64.getEncoder().encodeToString(fileContent);
|
||||||
@ -409,7 +411,7 @@ public class AIChatHandler implements IAIChatHandler {
|
|||||||
// 构建 ImageContent 对象
|
// 构建 ImageContent 对象
|
||||||
imageContents.add(ImageContent.from(base64Data, mimeType));
|
imageContents.add(ImageContent.from(base64Data, mimeType));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("读取文件失败: " + filePath, e);
|
log.error("读取文件失败: {}", imageUrl, e);
|
||||||
throw new RuntimeException("发送消息失败,读取文件异常:" + e.getMessage(), e);
|
throw new RuntimeException("发送消息失败,读取文件异常:" + e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -529,12 +531,13 @@ public class AIChatHandler implements IAIChatHandler {
|
|||||||
} else {
|
} else {
|
||||||
// 本地文件
|
// 本地文件
|
||||||
String filePath = uploadpath + File.separator + imageUrl;
|
String filePath = uploadpath + File.separator + imageUrl;
|
||||||
|
SsrfFileTypeFilter.checkPathTraversal(filePath);
|
||||||
Path path = Paths.get(filePath);
|
Path path = Paths.get(filePath);
|
||||||
fileContent = Files.readAllBytes(path);
|
fileContent = Files.readAllBytes(path);
|
||||||
}
|
}
|
||||||
originalImageBase64List.add(Base64.getEncoder().encodeToString(fileContent));
|
originalImageBase64List.add(Base64.getEncoder().encodeToString(fileContent));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("图片读取失败: " + imageUrl, e);
|
log.error("图片读取失败: {}", imageUrl, e);
|
||||||
throw new JeecgBootException("图片读取失败: " + imageUrl);
|
throw new JeecgBootException("图片读取失败: " + imageUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,6 +20,7 @@ import org.jeecg.common.system.query.QueryGenerator;
|
|||||||
import org.jeecg.common.system.util.JwtUtil;
|
import org.jeecg.common.system.util.JwtUtil;
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
import org.jeecg.common.util.*;
|
import org.jeecg.common.util.*;
|
||||||
|
import org.jeecg.common.util.filter.SsrfFileTypeFilter;
|
||||||
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
|
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
|
||||||
import org.jeecg.modules.message.enums.RangeDateEnum;
|
import org.jeecg.modules.message.enums.RangeDateEnum;
|
||||||
import org.jeecg.modules.message.websocket.WebSocket;
|
import org.jeecg.modules.message.websocket.WebSocket;
|
||||||
@ -142,6 +143,8 @@ public class SysAnnouncementController {
|
|||||||
// 代码逻辑说明: 标题处理xss攻击的问题
|
// 代码逻辑说明: 标题处理xss攻击的问题
|
||||||
String title = XssUtils.scriptXss(sysAnnouncement.getTitile());
|
String title = XssUtils.scriptXss(sysAnnouncement.getTitile());
|
||||||
sysAnnouncement.setTitile(title);
|
sysAnnouncement.setTitile(title);
|
||||||
|
// 【安全校验】校验附件文件名,防止路径遍历攻击
|
||||||
|
SsrfFileTypeFilter.checkPathTraversalBatch(sysAnnouncement.getFiles());
|
||||||
sysAnnouncement.setDelFlag(CommonConstant.DEL_FLAG_0.toString());
|
sysAnnouncement.setDelFlag(CommonConstant.DEL_FLAG_0.toString());
|
||||||
//未发布
|
//未发布
|
||||||
sysAnnouncement.setSendStatus(CommonSendStatus.UNPUBLISHED_STATUS_0);
|
sysAnnouncement.setSendStatus(CommonSendStatus.UNPUBLISHED_STATUS_0);
|
||||||
@ -173,6 +176,8 @@ public class SysAnnouncementController {
|
|||||||
// 代码逻辑说明: 标题处理xss攻击的问题
|
// 代码逻辑说明: 标题处理xss攻击的问题
|
||||||
String title = XssUtils.scriptXss(sysAnnouncement.getTitile());
|
String title = XssUtils.scriptXss(sysAnnouncement.getTitile());
|
||||||
sysAnnouncement.setTitile(title);
|
sysAnnouncement.setTitile(title);
|
||||||
|
// 【安全校验】校验附件文件名,防止路径遍历攻击
|
||||||
|
SsrfFileTypeFilter.checkPathTraversalBatch(sysAnnouncement.getFiles());
|
||||||
sysAnnouncement.setNoticeType(NoticeTypeEnum.NOTICE_TYPE_SYSTEM.getValue());
|
sysAnnouncement.setNoticeType(NoticeTypeEnum.NOTICE_TYPE_SYSTEM.getValue());
|
||||||
boolean ok = sysAnnouncementService.upDateAnnouncement(sysAnnouncement);
|
boolean ok = sysAnnouncementService.upDateAnnouncement(sysAnnouncement);
|
||||||
//TODO 返回false说明什么?
|
//TODO 返回false说明什么?
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import org.apache.shiro.SecurityUtils;
|
|||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
import org.jeecg.common.system.vo.LoginUser;
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
import org.jeecg.common.util.FileDownloadUtils;
|
import org.jeecg.common.util.FileDownloadUtils;
|
||||||
|
import org.jeecg.common.util.filter.SsrfFileTypeFilter;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.config.JeecgBaseConfig;
|
import org.jeecg.config.JeecgBaseConfig;
|
||||||
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
|
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
|
||||||
@ -303,6 +304,8 @@ public class SysAnnouncementServiceImpl extends ServiceImpl<SysAnnouncementMappe
|
|||||||
if (oConvertUtils.isEmpty(fileUrl)) {
|
if (oConvertUtils.isEmpty(fileUrl)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// 【安全校验】防止路径遍历攻击
|
||||||
|
SsrfFileTypeFilter.checkPathTraversal(fileUrl);
|
||||||
// 生成ZIP内文件名:避免重名,添加序号
|
// 生成ZIP内文件名:避免重名,添加序号
|
||||||
String fileName = FileDownloadUtils.generateFileName(fileUrl, i, fileUrls.length);
|
String fileName = FileDownloadUtils.generateFileName(fileUrl, i, fileUrls.length);
|
||||||
String uploadUrl = jeecgBaseConfig.getPath().getUpload();
|
String uploadUrl = jeecgBaseConfig.getPath().getUpload();
|
||||||
|
|||||||
Reference in New Issue
Block a user