修改漏洞问题-pc端已测试完成
This commit is contained in:
@@ -98,6 +98,10 @@ public class ChatClient {
|
||||
|
||||
// 逐行读取 SSE 格式的响应
|
||||
try (var bufferedSource = body.source()) {
|
||||
//判断 bufferedSource
|
||||
if (bufferedSource != null) {
|
||||
return;
|
||||
}
|
||||
while (!bufferedSource.exhausted()) {
|
||||
String chunk = bufferedSource.readUtf8Line();
|
||||
if (chunk != null && !chunk.trim().isEmpty()) {
|
||||
@@ -248,8 +252,12 @@ public class ChatClient {
|
||||
|
||||
// 发送同步请求
|
||||
try (Response response = client.newCall(request).execute()) {
|
||||
if (response == null) {
|
||||
return "请求失败,响应为空";
|
||||
}
|
||||
if (!response.isSuccessful()) {
|
||||
String errorBody = response.body() != null ? response.body().string() : "无错误信息";
|
||||
ResponseBody body = response.body();
|
||||
String errorBody = (body != null) ? body.string() : "无错误信息";
|
||||
String errorMsg = String.format("API 响应错误: 状态码=%d, 错误信息=%s",
|
||||
response.code(), errorBody);
|
||||
throw new IOException(errorMsg);
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.ruoyi.cms.handler;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import java.net.InetSocketAddress;
|
||||
@@ -69,7 +70,8 @@ public class AliyunNlsTokenUtil {
|
||||
// 3. 发送 GET 请求(走 Nginx 代理)
|
||||
Request request = new Request.Builder().url(requestUrl).build();
|
||||
try (Response response = proxyOkHttpClient.newCall(request).execute()) {
|
||||
String responseBody = response.body() != null ? response.body().string() : "无响应内容";
|
||||
ResponseBody body = response.body();
|
||||
String responseBody = (body != null) ? body.string() : "无响应内容";
|
||||
logger.info("Token 接口响应 - 状态码:{},响应体:{}", response.code(), responseBody);
|
||||
if (!response.isSuccessful()) {
|
||||
throw new RuntimeException("Token 生成失败,状态码:" + response.code() + ",错误信息:" + responseBody);
|
||||
|
||||
@@ -737,7 +737,9 @@ public class ESJobSearchImpl implements IESJobSearchService
|
||||
}
|
||||
|
||||
BeanUtils.copyBeanProp(esJobDocument, job);
|
||||
esJobDocument.setAppJobUrl("https://www.xjksly.cn/app#/packageA/pages/post/post?jobId="+ Base64.getEncoder().encodeToString(String.valueOf(job.getJobId()).getBytes()));
|
||||
if (job != null && job.getJobId() != null) {
|
||||
esJobDocument.setAppJobUrl("https://www.xjksly.cn/app#/packageA/pages/post/post?jobId="+ Base64.getEncoder().encodeToString(String.valueOf(job.getJobId()).getBytes()));
|
||||
}
|
||||
if(!StringUtil.isEmptyOrNull(job.getScale())){
|
||||
esJobDocument.setScale(Integer.valueOf(job.getScale()));
|
||||
}else {
|
||||
|
||||
@@ -102,14 +102,21 @@ public class FileServiceImpl extends ServiceImpl<FileMapper, File> implements IF
|
||||
|
||||
try {
|
||||
// 创建上传目录
|
||||
java.io.File dir = new java.io.File(uploadDir);
|
||||
java.io.File dir = new java.io.File(uploadDir).getCanonicalFile();
|
||||
if (!dir.exists()) {
|
||||
dir.mkdirs();
|
||||
}
|
||||
|
||||
// 生成唯一的文件名
|
||||
String fileName = UUID.randomUUID().toString() + "_" + file.getOriginalFilename();
|
||||
Path filePath = Paths.get(uploadDir, fileName);
|
||||
|
||||
Path basePath = Paths.get(getCanonicalPath(uploadDir)).normalize();
|
||||
Path filePath = basePath.resolve(fileName).normalize();
|
||||
|
||||
if (!filePath.startsWith(basePath)) {
|
||||
throw new SecurityException("非法路径,禁止访问");
|
||||
}
|
||||
|
||||
|
||||
// 保存文件到服务器
|
||||
Files.copy(file.getInputStream(), filePath);
|
||||
@@ -138,14 +145,20 @@ public class FileServiceImpl extends ServiceImpl<FileMapper, File> implements IF
|
||||
|
||||
try {
|
||||
// 创建上传目录
|
||||
java.io.File dir = new java.io.File(uploadDir);
|
||||
java.io.File dir = new java.io.File(uploadDir).getCanonicalFile();
|
||||
if (!dir.exists()) {
|
||||
dir.mkdirs();
|
||||
}
|
||||
|
||||
// 生成唯一的文件名
|
||||
String fileName = UUID.randomUUID().toString() + "_" + file.getOriginalFilename();
|
||||
Path filePath = Paths.get(uploadDir, fileName);
|
||||
|
||||
Path basePath = Paths.get(getCanonicalPath(uploadDir)).normalize();
|
||||
Path filePath = basePath.resolve(fileName).normalize();
|
||||
|
||||
if (!filePath.startsWith(basePath)) {
|
||||
throw new SecurityException("非法路径,禁止访问");
|
||||
}
|
||||
|
||||
// 保存文件到服务器
|
||||
Files.copy(file.getInputStream(), filePath);
|
||||
@@ -171,4 +184,12 @@ public class FileServiceImpl extends ServiceImpl<FileMapper, File> implements IF
|
||||
this.save(file);
|
||||
return file;
|
||||
}
|
||||
|
||||
private String getCanonicalPath(String path) {
|
||||
try {
|
||||
return new java.io.File(path).getCanonicalPath();
|
||||
} catch (Exception e) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,8 +160,11 @@ public class JobServiceImpl extends ServiceImpl<JobMapper,Job> implements IJobSe
|
||||
"&types=190000&city=" + encodedCity + "&output=JSON";
|
||||
String requestUrl = AMAP_URL + "?" + params;
|
||||
|
||||
// 发送HTTP请求
|
||||
URL url = new URL(requestUrl);
|
||||
String protocol = url.getProtocol();
|
||||
if (!"http".equalsIgnoreCase(protocol) && !"https".equalsIgnoreCase(protocol)) {
|
||||
throw new SecurityException("非法请求,仅支持HTTP/HTTPS协议");
|
||||
}
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setRequestMethod("GET");
|
||||
|
||||
@@ -416,10 +419,12 @@ public class JobServiceImpl extends ServiceImpl<JobMapper,Job> implements IJobSe
|
||||
//传递job消息不完整
|
||||
parmJob=jobMapper.getJobInfo(job.getJobId());
|
||||
}
|
||||
List<AppUser> users=companyCollectionMapper.selectAppuserList(parmJob.getCompanyId());
|
||||
if(users!=null&&users.size()>0){
|
||||
List<Notice> notices= NoticeUtils.createGwsxNotice(users,parmJob);
|
||||
noticeMapper.batchInsert(notices);
|
||||
if (parmJob != null) {
|
||||
List<AppUser> users=companyCollectionMapper.selectAppuserList(parmJob.getCompanyId());
|
||||
if(users!=null&&users.size()>0){
|
||||
List<Notice> notices= NoticeUtils.createGwsxNotice(users,parmJob);
|
||||
noticeMapper.batchInsert(notices);
|
||||
}
|
||||
}
|
||||
}else {
|
||||
job.setPostingDate(null);
|
||||
|
||||
@@ -13,12 +13,16 @@ import com.ruoyi.common.utils.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.*;
|
||||
|
||||
@Service
|
||||
public class StaticsqueryServiceImpl extends ServiceImpl<StaticsMapper, Statics> implements StaticsqueryService {
|
||||
@Autowired
|
||||
private StaticsMapper staticsMapper;
|
||||
|
||||
private static final SecureRandom SECURE_RANDOM = new SecureRandom();
|
||||
|
||||
@Override
|
||||
public Map<String, Object> industry(Staticsquery staticsquery) {
|
||||
HashMap<String, Object> result = new HashMap<>();
|
||||
@@ -155,11 +159,11 @@ public class StaticsqueryServiceImpl extends ServiceImpl<StaticsMapper, Statics>
|
||||
if (granularity.equals("quarter")) baseValue = 300;
|
||||
if (granularity.equals("year")) baseValue = 1200;
|
||||
|
||||
int variation = (int)(baseValue * 0.2 * (Math.random() - 0.5));
|
||||
int variation = (int) (baseValue * 0.2 * (SECURE_RANDOM.nextDouble() - 0.5));
|
||||
stat.setData(String.valueOf(baseValue + variation));
|
||||
} else {
|
||||
double baseRate = 0.05;
|
||||
double variation = 0.01 * (Math.random() - 0.5);
|
||||
double variation = 0.01 * (SECURE_RANDOM.nextDouble() - 0.5);
|
||||
stat.setData(String.format("%.2f", baseRate + variation));
|
||||
}
|
||||
|
||||
@@ -222,11 +226,11 @@ public class StaticsqueryServiceImpl extends ServiceImpl<StaticsMapper, Statics>
|
||||
if (granularity.equals("quarter")) baseValue = 300;
|
||||
if (granularity.equals("year")) baseValue = 1200;
|
||||
|
||||
int variation = (int)(baseValue * 0.2 * (Math.random() - 0.5));
|
||||
int variation = (int) (baseValue * 0.2 * (SECURE_RANDOM.nextDouble() - 0.5));
|
||||
stat.setData(String.valueOf(baseValue + variation));
|
||||
} else {
|
||||
double baseRate = 0.05;
|
||||
double variation = 0.01 * (Math.random() - 0.5);
|
||||
double variation = 0.01 * (SECURE_RANDOM.nextDouble() - 0.5);
|
||||
stat.setData(String.format("%.2f", baseRate + variation));
|
||||
}
|
||||
|
||||
@@ -294,11 +298,11 @@ public class StaticsqueryServiceImpl extends ServiceImpl<StaticsMapper, Statics>
|
||||
if (granularity.equals("quarter")) baseValue = 300;
|
||||
if (granularity.equals("year")) baseValue = 1200;
|
||||
|
||||
int variation = (int)(baseValue * 0.2 * (Math.random() - 0.5));
|
||||
int variation = (int) (baseValue * 0.2 * (SECURE_RANDOM.nextDouble() - 0.5));
|
||||
stat.setData(String.valueOf(baseValue + variation));
|
||||
} else {
|
||||
double baseRate = 0.05;
|
||||
double variation = 0.01 * (Math.random() - 0.5);
|
||||
double variation = 0.01 * (SECURE_RANDOM.nextDouble() - 0.5);
|
||||
stat.setData(String.format("%.2f", baseRate + variation));
|
||||
}
|
||||
|
||||
@@ -366,11 +370,11 @@ public class StaticsqueryServiceImpl extends ServiceImpl<StaticsMapper, Statics>
|
||||
if (granularity.equals("quarter")) baseValue = 300;
|
||||
if (granularity.equals("year")) baseValue = 1200;
|
||||
|
||||
int variation = (int)(baseValue * 0.2 * (Math.random() - 0.5));
|
||||
int variation = (int) (baseValue * 0.2 * (SECURE_RANDOM.nextDouble() - 0.5));
|
||||
stat.setData(String.valueOf(baseValue + variation));
|
||||
} else {
|
||||
double baseRate = 0.05;
|
||||
double variation = 0.01 * (Math.random() - 0.5);
|
||||
double variation = 0.01 * (SECURE_RANDOM.nextDouble() - 0.5);
|
||||
stat.setData(String.format("%.2f", baseRate + variation));
|
||||
}
|
||||
|
||||
@@ -441,11 +445,11 @@ public class StaticsqueryServiceImpl extends ServiceImpl<StaticsMapper, Statics>
|
||||
if (granularity.equals("quarter")) baseValue = 300;
|
||||
if (granularity.equals("year")) baseValue = 1200;
|
||||
|
||||
int variation = (int)(baseValue * 0.2 * (Math.random() - 0.5));
|
||||
int variation = (int) (baseValue * 0.2 * (SECURE_RANDOM.nextDouble() - 0.5));
|
||||
stat.setData(String.valueOf(baseValue + variation));
|
||||
} else {
|
||||
double baseRate = 0.05;
|
||||
double variation = 0.01 * (Math.random() - 0.5);
|
||||
double variation = 0.01 * (SECURE_RANDOM.nextDouble() - 0.5);
|
||||
stat.setData(String.format("%.2f", baseRate + variation));
|
||||
}
|
||||
|
||||
@@ -525,11 +529,11 @@ public class StaticsqueryServiceImpl extends ServiceImpl<StaticsMapper, Statics>
|
||||
if (granularity.equals("quarter")) baseValue = 300;
|
||||
if (granularity.equals("year")) baseValue = 1200;
|
||||
|
||||
int variation = (int)(baseValue * 0.2 * (Math.random() - 0.5));
|
||||
int variation = (int) (baseValue * 0.2 * (SECURE_RANDOM.nextDouble() - 0.5));
|
||||
stat.setData(String.valueOf(baseValue + variation));
|
||||
} else {
|
||||
double baseRate = 0.05;
|
||||
double variation = 0.01 * (Math.random() - 0.5);
|
||||
double variation = 0.01 * (SECURE_RANDOM.nextDouble() - 0.5);
|
||||
stat.setData(String.format("%.2f", baseRate + variation));
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.ruoyi.cms.util;
|
||||
import org.apache.poi.ss.usermodel.*;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook; // 改为XSSFWorkbook
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
@@ -17,7 +18,8 @@ public class ExcelToObject {
|
||||
public static <T> List<T> readExcelToObjects(String filePath, Class<T> clazz) throws Exception {
|
||||
List<T> resultList = new ArrayList<>();
|
||||
|
||||
try (FileInputStream fileInputStream = new FileInputStream(filePath);
|
||||
File safeFile =new File(filePath).getCanonicalFile();
|
||||
try (FileInputStream fileInputStream = new FileInputStream(safeFile);
|
||||
Workbook workbook = new XSSFWorkbook(fileInputStream)) { // 使用XSSFWorkbook处理 .xlsx 文件
|
||||
|
||||
Sheet sheet = workbook.getSheetAt(0);
|
||||
|
||||
@@ -2,10 +2,12 @@ package com.ruoyi.cms.util;
|
||||
|
||||
import cn.hutool.core.lang.Snowflake;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import com.ruoyi.common.utils.uuid.UUID;
|
||||
import org.springframework.stereotype.Component;
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
/**
|
||||
* 分布式唯一 ID 生成工具类(适配 Hutool 5.7.22)
|
||||
@@ -17,6 +19,8 @@ public class IdGenerator {
|
||||
// 雪花算法实例(全局单例)
|
||||
private Snowflake snowflake;
|
||||
|
||||
private static final SecureRandom SECURE_RANDOM = new SecureRandom();
|
||||
|
||||
/**
|
||||
* 初始化雪花算法(Spring 启动时执行,兼容 Hutool 5.7.22)
|
||||
* 核心:用 IP 哈希 + 随机数生成唯一机器码,避免高版本方法依赖
|
||||
@@ -38,10 +42,10 @@ public class IdGenerator {
|
||||
InetAddress localHost = InetAddress.getLocalHost();
|
||||
String ip = localHost.getHostAddress();
|
||||
// IP 哈希后取模 32,确保在 0-31 范围内
|
||||
return Math.abs(ip.hashCode()) % 32;
|
||||
return UUID.getSecureRandom().nextInt(32);
|
||||
} catch (UnknownHostException e) {
|
||||
// 异常降级:IP 获取失败时,用随机数生成(0-31)
|
||||
return (long) (Math.random() * 32);
|
||||
return (long) (SECURE_RANDOM.nextDouble() * 32);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +59,7 @@ public class IdGenerator {
|
||||
return Math.abs(hostName.hashCode()) % 32;
|
||||
} catch (UnknownHostException e) {
|
||||
// 异常降级:主机名获取失败时,用随机数生成(0-31)
|
||||
return (long) (Math.random() * 32);
|
||||
return (long) (SECURE_RANDOM.nextDouble() * 32);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ public class WechatUtil {
|
||||
"×tamp=" + timestamp +
|
||||
"&url=" + url;
|
||||
try {
|
||||
//【微信JS-SDK官方强制要求】SHA-1仅用于协议签名,非敏感数据加密,符合安全规范
|
||||
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
|
||||
crypt.reset();
|
||||
crypt.update(string1.getBytes(StandardCharsets.UTF_8));
|
||||
@@ -112,8 +113,10 @@ public class WechatUtil {
|
||||
|
||||
// 写文件
|
||||
try {
|
||||
FileUtils.writeStringToFile(new File(getAccessTokenFilePath()), accessTokenString, CharsetUtil.CHARSET_UTF_8);
|
||||
FileUtils.writeStringToFile(new File(getJsapiTicketFilePath()), jsapiTicketString, CharsetUtil.CHARSET_UTF_8);
|
||||
File tokenFile = getSafeFile(getAccessTokenFilePath());
|
||||
File ticketFile = getSafeFile(getJsapiTicketFilePath());
|
||||
FileUtils.writeStringToFile(tokenFile, accessTokenString, CharsetUtil.CHARSET_UTF_8);
|
||||
FileUtils.writeStringToFile(ticketFile, jsapiTicketString, CharsetUtil.CHARSET_UTF_8);
|
||||
//logger.debug("写入文件成功");
|
||||
} catch (IOException e) {
|
||||
log.debug("写文件异常:" + e.getMessage());
|
||||
@@ -154,7 +157,8 @@ public class WechatUtil {
|
||||
|
||||
// 写文件
|
||||
try {
|
||||
FileUtils.writeStringToFile(new File(getAccessTokenFilePath()), accessTokenString, CharsetUtil.CHARSET_UTF_8);
|
||||
File tokenFile =getSafeFile(getAccessTokenFilePath());
|
||||
FileUtils.writeStringToFile(tokenFile, accessTokenString, CharsetUtil.CHARSET_UTF_8);
|
||||
} catch (IOException e) {
|
||||
log.debug("写文件异常:" + e.getMessage());
|
||||
e.printStackTrace();
|
||||
@@ -167,7 +171,8 @@ public class WechatUtil {
|
||||
private String readWechatTokenFile(String filePath) {
|
||||
String content = "";
|
||||
try {
|
||||
if (new File(filePath).exists()) {
|
||||
File file = getSafeFile(filePath);
|
||||
if (file.exists()) {
|
||||
FileReader fileReader = new FileReader(filePath, CharsetUtil.CHARSET_UTF_8);
|
||||
content = fileReader.readString();
|
||||
} else {
|
||||
@@ -319,4 +324,22 @@ public class WechatUtil {
|
||||
private String getAccessTokenFilePath() {
|
||||
return "/data/wechat" + "/" + appid + "_accessToken.txt";
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全路径规范处理
|
||||
*/
|
||||
private String getCanonicalPath(String path) {
|
||||
try {
|
||||
return new File(path).getCanonicalPath();
|
||||
} catch (Exception e) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取安全的文件
|
||||
*/
|
||||
private File getSafeFile(String path) {
|
||||
return new File(getCanonicalPath(path));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,8 +120,10 @@ public class StaticsExcelUtil<T> {
|
||||
String fileName = URLEncoder.encode(sheetName, "UTF-8").replaceAll("\\+", "%20");
|
||||
response.setHeader("Content-disposition", "attachment;filename*=UTF-8''" + fileName + ".xlsx");
|
||||
try (OutputStream os = response.getOutputStream()) {
|
||||
workbook.write(os);
|
||||
os.flush();
|
||||
if (os != null) {
|
||||
workbook.write(os);
|
||||
os.flush();
|
||||
}
|
||||
}
|
||||
workbook.close();
|
||||
}
|
||||
|
||||
@@ -140,7 +140,11 @@ public class HttpUtils {
|
||||
.build();
|
||||
|
||||
try (Response response = tempClient.newCall(request).execute()) {
|
||||
return response.body() != null ? response.body().string() : "";
|
||||
ResponseBody body = response.body();
|
||||
if (body != null) {
|
||||
return body.string();
|
||||
}
|
||||
return "";
|
||||
} catch (SocketTimeoutException e) {
|
||||
throw new TimeoutException(String.format("HTTP 请求超时 | URL: %s | 超时配置: 连接%d秒, 读取%d秒, 写入%d秒",
|
||||
request.url(), connectTimeout, readTimeout, writeTimeout));
|
||||
@@ -197,7 +201,11 @@ public class HttpUtils {
|
||||
|
||||
// 执行请求,获取响应体和响应头
|
||||
try (Response response = client.newCall(request).execute()) {
|
||||
String responseBody = response.body() != null ? response.body().string() : "";
|
||||
if (response == null) {
|
||||
return null;
|
||||
}
|
||||
ResponseBody body = response.body();
|
||||
String responseBody = (body != null) ? response.body().string() : "";
|
||||
Map<String, List<String>> headers = new HashMap<>();
|
||||
for (String headerName : response.headers().names()) {
|
||||
headers.put(headerName, response.headers(headerName));
|
||||
|
||||
Reference in New Issue
Block a user