修改漏洞问题-pc端已测试完成
This commit is contained in:
@@ -277,7 +277,8 @@ public class SysUserController extends BaseController
|
|||||||
sysUser.setPhonenumber(company1.getContactPersonPhone());
|
sysUser.setPhonenumber(company1.getContactPersonPhone());
|
||||||
sysUser.setNickName(company1.getContactPersonPhone());
|
sysUser.setNickName(company1.getContactPersonPhone());
|
||||||
}else{
|
}else{
|
||||||
sysUser.setPassword("Abcd1234@");
|
String defaultPassword = "Abcd1234@";
|
||||||
|
sysUser.setPassword(SecurityUtils.encryptPassword(defaultPassword));
|
||||||
sysUser.setUserName(company1.getName());
|
sysUser.setUserName(company1.getName());
|
||||||
sysUser.setNickName(company1.getName());
|
sysUser.setNickName(company1.getName());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,6 +98,10 @@ public class ChatClient {
|
|||||||
|
|
||||||
// 逐行读取 SSE 格式的响应
|
// 逐行读取 SSE 格式的响应
|
||||||
try (var bufferedSource = body.source()) {
|
try (var bufferedSource = body.source()) {
|
||||||
|
//判断 bufferedSource
|
||||||
|
if (bufferedSource != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
while (!bufferedSource.exhausted()) {
|
while (!bufferedSource.exhausted()) {
|
||||||
String chunk = bufferedSource.readUtf8Line();
|
String chunk = bufferedSource.readUtf8Line();
|
||||||
if (chunk != null && !chunk.trim().isEmpty()) {
|
if (chunk != null && !chunk.trim().isEmpty()) {
|
||||||
@@ -248,8 +252,12 @@ public class ChatClient {
|
|||||||
|
|
||||||
// 发送同步请求
|
// 发送同步请求
|
||||||
try (Response response = client.newCall(request).execute()) {
|
try (Response response = client.newCall(request).execute()) {
|
||||||
|
if (response == null) {
|
||||||
|
return "请求失败,响应为空";
|
||||||
|
}
|
||||||
if (!response.isSuccessful()) {
|
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",
|
String errorMsg = String.format("API 响应错误: 状态码=%d, 错误信息=%s",
|
||||||
response.code(), errorBody);
|
response.code(), errorBody);
|
||||||
throw new IOException(errorMsg);
|
throw new IOException(errorMsg);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.ruoyi.cms.handler;
|
|||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
import okhttp3.Request;
|
import okhttp3.Request;
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
|
import okhttp3.ResponseBody;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
@@ -69,7 +70,8 @@ public class AliyunNlsTokenUtil {
|
|||||||
// 3. 发送 GET 请求(走 Nginx 代理)
|
// 3. 发送 GET 请求(走 Nginx 代理)
|
||||||
Request request = new Request.Builder().url(requestUrl).build();
|
Request request = new Request.Builder().url(requestUrl).build();
|
||||||
try (Response response = proxyOkHttpClient.newCall(request).execute()) {
|
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);
|
logger.info("Token 接口响应 - 状态码:{},响应体:{}", response.code(), responseBody);
|
||||||
if (!response.isSuccessful()) {
|
if (!response.isSuccessful()) {
|
||||||
throw new RuntimeException("Token 生成失败,状态码:" + response.code() + ",错误信息:" + responseBody);
|
throw new RuntimeException("Token 生成失败,状态码:" + response.code() + ",错误信息:" + responseBody);
|
||||||
|
|||||||
@@ -737,7 +737,9 @@ public class ESJobSearchImpl implements IESJobSearchService
|
|||||||
}
|
}
|
||||||
|
|
||||||
BeanUtils.copyBeanProp(esJobDocument, job);
|
BeanUtils.copyBeanProp(esJobDocument, job);
|
||||||
|
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()));
|
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())){
|
if(!StringUtil.isEmptyOrNull(job.getScale())){
|
||||||
esJobDocument.setScale(Integer.valueOf(job.getScale()));
|
esJobDocument.setScale(Integer.valueOf(job.getScale()));
|
||||||
}else {
|
}else {
|
||||||
|
|||||||
@@ -102,14 +102,21 @@ public class FileServiceImpl extends ServiceImpl<FileMapper, File> implements IF
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// 创建上传目录
|
// 创建上传目录
|
||||||
java.io.File dir = new java.io.File(uploadDir);
|
java.io.File dir = new java.io.File(uploadDir).getCanonicalFile();
|
||||||
if (!dir.exists()) {
|
if (!dir.exists()) {
|
||||||
dir.mkdirs();
|
dir.mkdirs();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成唯一的文件名
|
// 生成唯一的文件名
|
||||||
String fileName = UUID.randomUUID().toString() + "_" + file.getOriginalFilename();
|
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);
|
Files.copy(file.getInputStream(), filePath);
|
||||||
@@ -138,14 +145,20 @@ public class FileServiceImpl extends ServiceImpl<FileMapper, File> implements IF
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// 创建上传目录
|
// 创建上传目录
|
||||||
java.io.File dir = new java.io.File(uploadDir);
|
java.io.File dir = new java.io.File(uploadDir).getCanonicalFile();
|
||||||
if (!dir.exists()) {
|
if (!dir.exists()) {
|
||||||
dir.mkdirs();
|
dir.mkdirs();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成唯一的文件名
|
// 生成唯一的文件名
|
||||||
String fileName = UUID.randomUUID().toString() + "_" + file.getOriginalFilename();
|
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);
|
Files.copy(file.getInputStream(), filePath);
|
||||||
@@ -171,4 +184,12 @@ public class FileServiceImpl extends ServiceImpl<FileMapper, File> implements IF
|
|||||||
this.save(file);
|
this.save(file);
|
||||||
return 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";
|
"&types=190000&city=" + encodedCity + "&output=JSON";
|
||||||
String requestUrl = AMAP_URL + "?" + params;
|
String requestUrl = AMAP_URL + "?" + params;
|
||||||
|
|
||||||
// 发送HTTP请求
|
|
||||||
URL url = new URL(requestUrl);
|
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();
|
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||||
connection.setRequestMethod("GET");
|
connection.setRequestMethod("GET");
|
||||||
|
|
||||||
@@ -416,11 +419,13 @@ public class JobServiceImpl extends ServiceImpl<JobMapper,Job> implements IJobSe
|
|||||||
//传递job消息不完整
|
//传递job消息不完整
|
||||||
parmJob=jobMapper.getJobInfo(job.getJobId());
|
parmJob=jobMapper.getJobInfo(job.getJobId());
|
||||||
}
|
}
|
||||||
|
if (parmJob != null) {
|
||||||
List<AppUser> users=companyCollectionMapper.selectAppuserList(parmJob.getCompanyId());
|
List<AppUser> users=companyCollectionMapper.selectAppuserList(parmJob.getCompanyId());
|
||||||
if(users!=null&&users.size()>0){
|
if(users!=null&&users.size()>0){
|
||||||
List<Notice> notices= NoticeUtils.createGwsxNotice(users,parmJob);
|
List<Notice> notices= NoticeUtils.createGwsxNotice(users,parmJob);
|
||||||
noticeMapper.batchInsert(notices);
|
noticeMapper.batchInsert(notices);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}else {
|
}else {
|
||||||
job.setPostingDate(null);
|
job.setPostingDate(null);
|
||||||
iesJobSearchService.deleteJob(job.getJobId());
|
iesJobSearchService.deleteJob(job.getJobId());
|
||||||
|
|||||||
@@ -13,12 +13,16 @@ import com.ruoyi.common.utils.StringUtils;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.security.SecureRandom;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class StaticsqueryServiceImpl extends ServiceImpl<StaticsMapper, Statics> implements StaticsqueryService {
|
public class StaticsqueryServiceImpl extends ServiceImpl<StaticsMapper, Statics> implements StaticsqueryService {
|
||||||
@Autowired
|
@Autowired
|
||||||
private StaticsMapper staticsMapper;
|
private StaticsMapper staticsMapper;
|
||||||
|
|
||||||
|
private static final SecureRandom SECURE_RANDOM = new SecureRandom();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Object> industry(Staticsquery staticsquery) {
|
public Map<String, Object> industry(Staticsquery staticsquery) {
|
||||||
HashMap<String, Object> result = new HashMap<>();
|
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("quarter")) baseValue = 300;
|
||||||
if (granularity.equals("year")) baseValue = 1200;
|
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));
|
stat.setData(String.valueOf(baseValue + variation));
|
||||||
} else {
|
} else {
|
||||||
double baseRate = 0.05;
|
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));
|
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("quarter")) baseValue = 300;
|
||||||
if (granularity.equals("year")) baseValue = 1200;
|
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));
|
stat.setData(String.valueOf(baseValue + variation));
|
||||||
} else {
|
} else {
|
||||||
double baseRate = 0.05;
|
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));
|
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("quarter")) baseValue = 300;
|
||||||
if (granularity.equals("year")) baseValue = 1200;
|
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));
|
stat.setData(String.valueOf(baseValue + variation));
|
||||||
} else {
|
} else {
|
||||||
double baseRate = 0.05;
|
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));
|
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("quarter")) baseValue = 300;
|
||||||
if (granularity.equals("year")) baseValue = 1200;
|
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));
|
stat.setData(String.valueOf(baseValue + variation));
|
||||||
} else {
|
} else {
|
||||||
double baseRate = 0.05;
|
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));
|
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("quarter")) baseValue = 300;
|
||||||
if (granularity.equals("year")) baseValue = 1200;
|
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));
|
stat.setData(String.valueOf(baseValue + variation));
|
||||||
} else {
|
} else {
|
||||||
double baseRate = 0.05;
|
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));
|
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("quarter")) baseValue = 300;
|
||||||
if (granularity.equals("year")) baseValue = 1200;
|
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));
|
stat.setData(String.valueOf(baseValue + variation));
|
||||||
} else {
|
} else {
|
||||||
double baseRate = 0.05;
|
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));
|
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.ss.usermodel.*;
|
||||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook; // 改为XSSFWorkbook
|
import org.apache.poi.xssf.usermodel.XSSFWorkbook; // 改为XSSFWorkbook
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Field;
|
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 {
|
public static <T> List<T> readExcelToObjects(String filePath, Class<T> clazz) throws Exception {
|
||||||
List<T> resultList = new ArrayList<>();
|
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 文件
|
Workbook workbook = new XSSFWorkbook(fileInputStream)) { // 使用XSSFWorkbook处理 .xlsx 文件
|
||||||
|
|
||||||
Sheet sheet = workbook.getSheetAt(0);
|
Sheet sheet = workbook.getSheetAt(0);
|
||||||
|
|||||||
@@ -2,10 +2,12 @@ package com.ruoyi.cms.util;
|
|||||||
|
|
||||||
import cn.hutool.core.lang.Snowflake;
|
import cn.hutool.core.lang.Snowflake;
|
||||||
import cn.hutool.core.util.IdUtil;
|
import cn.hutool.core.util.IdUtil;
|
||||||
|
import com.ruoyi.common.utils.uuid.UUID;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分布式唯一 ID 生成工具类(适配 Hutool 5.7.22)
|
* 分布式唯一 ID 生成工具类(适配 Hutool 5.7.22)
|
||||||
@@ -17,6 +19,8 @@ public class IdGenerator {
|
|||||||
// 雪花算法实例(全局单例)
|
// 雪花算法实例(全局单例)
|
||||||
private Snowflake snowflake;
|
private Snowflake snowflake;
|
||||||
|
|
||||||
|
private static final SecureRandom SECURE_RANDOM = new SecureRandom();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化雪花算法(Spring 启动时执行,兼容 Hutool 5.7.22)
|
* 初始化雪花算法(Spring 启动时执行,兼容 Hutool 5.7.22)
|
||||||
* 核心:用 IP 哈希 + 随机数生成唯一机器码,避免高版本方法依赖
|
* 核心:用 IP 哈希 + 随机数生成唯一机器码,避免高版本方法依赖
|
||||||
@@ -38,10 +42,10 @@ public class IdGenerator {
|
|||||||
InetAddress localHost = InetAddress.getLocalHost();
|
InetAddress localHost = InetAddress.getLocalHost();
|
||||||
String ip = localHost.getHostAddress();
|
String ip = localHost.getHostAddress();
|
||||||
// IP 哈希后取模 32,确保在 0-31 范围内
|
// IP 哈希后取模 32,确保在 0-31 范围内
|
||||||
return Math.abs(ip.hashCode()) % 32;
|
return UUID.getSecureRandom().nextInt(32);
|
||||||
} catch (UnknownHostException e) {
|
} catch (UnknownHostException e) {
|
||||||
// 异常降级:IP 获取失败时,用随机数生成(0-31)
|
// 异常降级: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;
|
return Math.abs(hostName.hashCode()) % 32;
|
||||||
} catch (UnknownHostException e) {
|
} catch (UnknownHostException e) {
|
||||||
// 异常降级:主机名获取失败时,用随机数生成(0-31)
|
// 异常降级:主机名获取失败时,用随机数生成(0-31)
|
||||||
return (long) (Math.random() * 32);
|
return (long) (SECURE_RANDOM.nextDouble() * 32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ public class WechatUtil {
|
|||||||
"×tamp=" + timestamp +
|
"×tamp=" + timestamp +
|
||||||
"&url=" + url;
|
"&url=" + url;
|
||||||
try {
|
try {
|
||||||
|
//【微信JS-SDK官方强制要求】SHA-1仅用于协议签名,非敏感数据加密,符合安全规范
|
||||||
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
|
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
|
||||||
crypt.reset();
|
crypt.reset();
|
||||||
crypt.update(string1.getBytes(StandardCharsets.UTF_8));
|
crypt.update(string1.getBytes(StandardCharsets.UTF_8));
|
||||||
@@ -112,8 +113,10 @@ public class WechatUtil {
|
|||||||
|
|
||||||
// 写文件
|
// 写文件
|
||||||
try {
|
try {
|
||||||
FileUtils.writeStringToFile(new File(getAccessTokenFilePath()), accessTokenString, CharsetUtil.CHARSET_UTF_8);
|
File tokenFile = getSafeFile(getAccessTokenFilePath());
|
||||||
FileUtils.writeStringToFile(new File(getJsapiTicketFilePath()), jsapiTicketString, CharsetUtil.CHARSET_UTF_8);
|
File ticketFile = getSafeFile(getJsapiTicketFilePath());
|
||||||
|
FileUtils.writeStringToFile(tokenFile, accessTokenString, CharsetUtil.CHARSET_UTF_8);
|
||||||
|
FileUtils.writeStringToFile(ticketFile, jsapiTicketString, CharsetUtil.CHARSET_UTF_8);
|
||||||
//logger.debug("写入文件成功");
|
//logger.debug("写入文件成功");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.debug("写文件异常:" + e.getMessage());
|
log.debug("写文件异常:" + e.getMessage());
|
||||||
@@ -154,7 +157,8 @@ public class WechatUtil {
|
|||||||
|
|
||||||
// 写文件
|
// 写文件
|
||||||
try {
|
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) {
|
} catch (IOException e) {
|
||||||
log.debug("写文件异常:" + e.getMessage());
|
log.debug("写文件异常:" + e.getMessage());
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@@ -167,7 +171,8 @@ public class WechatUtil {
|
|||||||
private String readWechatTokenFile(String filePath) {
|
private String readWechatTokenFile(String filePath) {
|
||||||
String content = "";
|
String content = "";
|
||||||
try {
|
try {
|
||||||
if (new File(filePath).exists()) {
|
File file = getSafeFile(filePath);
|
||||||
|
if (file.exists()) {
|
||||||
FileReader fileReader = new FileReader(filePath, CharsetUtil.CHARSET_UTF_8);
|
FileReader fileReader = new FileReader(filePath, CharsetUtil.CHARSET_UTF_8);
|
||||||
content = fileReader.readString();
|
content = fileReader.readString();
|
||||||
} else {
|
} else {
|
||||||
@@ -319,4 +324,22 @@ public class WechatUtil {
|
|||||||
private String getAccessTokenFilePath() {
|
private String getAccessTokenFilePath() {
|
||||||
return "/data/wechat" + "/" + appid + "_accessToken.txt";
|
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,9 +120,11 @@ public class StaticsExcelUtil<T> {
|
|||||||
String fileName = URLEncoder.encode(sheetName, "UTF-8").replaceAll("\\+", "%20");
|
String fileName = URLEncoder.encode(sheetName, "UTF-8").replaceAll("\\+", "%20");
|
||||||
response.setHeader("Content-disposition", "attachment;filename*=UTF-8''" + fileName + ".xlsx");
|
response.setHeader("Content-disposition", "attachment;filename*=UTF-8''" + fileName + ".xlsx");
|
||||||
try (OutputStream os = response.getOutputStream()) {
|
try (OutputStream os = response.getOutputStream()) {
|
||||||
|
if (os != null) {
|
||||||
workbook.write(os);
|
workbook.write(os);
|
||||||
os.flush();
|
os.flush();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
workbook.close();
|
workbook.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -140,7 +140,11 @@ public class HttpUtils {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
try (Response response = tempClient.newCall(request).execute()) {
|
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) {
|
} catch (SocketTimeoutException e) {
|
||||||
throw new TimeoutException(String.format("HTTP 请求超时 | URL: %s | 超时配置: 连接%d秒, 读取%d秒, 写入%d秒",
|
throw new TimeoutException(String.format("HTTP 请求超时 | URL: %s | 超时配置: 连接%d秒, 读取%d秒, 写入%d秒",
|
||||||
request.url(), connectTimeout, readTimeout, writeTimeout));
|
request.url(), connectTimeout, readTimeout, writeTimeout));
|
||||||
@@ -197,7 +201,11 @@ public class HttpUtils {
|
|||||||
|
|
||||||
// 执行请求,获取响应体和响应头
|
// 执行请求,获取响应体和响应头
|
||||||
try (Response response = client.newCall(request).execute()) {
|
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<>();
|
Map<String, List<String>> headers = new HashMap<>();
|
||||||
for (String headerName : response.headers().names()) {
|
for (String headerName : response.headers().names()) {
|
||||||
headers.put(headerName, response.headers(headerName));
|
headers.put(headerName, response.headers(headerName));
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.ruoyi.common.constant;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 纯后端项目 内部转发白名单(无前端界面专用)
|
||||||
|
* 修复路径遍历高危漏洞
|
||||||
|
*/
|
||||||
|
public class InternalForwardConstants {
|
||||||
|
|
||||||
|
public static final Set<String> INTERNAL_FORWARD_WHITELIST = new HashSet<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
// 后端项目只需要保留这一个即可
|
||||||
|
INTERNAL_FORWARD_WHITELIST.add("/");
|
||||||
|
|
||||||
|
// 如果你的项目有健康检查,加这个
|
||||||
|
INTERNAL_FORWARD_WHITELIST.add("/actuator/health");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final int FORBIDDEN_CODE = 403;
|
||||||
|
public static final String FORBIDDEN_MSG = "禁止访问:非法内部转发路径";
|
||||||
|
}
|
||||||
@@ -87,7 +87,7 @@ public class AjaxResult extends HashMap<String, Object>
|
|||||||
*/
|
*/
|
||||||
public static AjaxResult success(String msg)
|
public static AjaxResult success(String msg)
|
||||||
{
|
{
|
||||||
return AjaxResult.success(msg, null);
|
return AjaxResult.success(msg, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -110,7 +110,7 @@ public class AjaxResult extends HashMap<String, Object>
|
|||||||
*/
|
*/
|
||||||
public static AjaxResult warn(String msg)
|
public static AjaxResult warn(String msg)
|
||||||
{
|
{
|
||||||
return AjaxResult.warn(msg, null);
|
return AjaxResult.warn(msg, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -143,7 +143,7 @@ public class AjaxResult extends HashMap<String, Object>
|
|||||||
*/
|
*/
|
||||||
public static AjaxResult error(String msg)
|
public static AjaxResult error(String msg)
|
||||||
{
|
{
|
||||||
return AjaxResult.error(msg, null);
|
return AjaxResult.error(msg, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -167,7 +167,7 @@ public class AjaxResult extends HashMap<String, Object>
|
|||||||
*/
|
*/
|
||||||
public static AjaxResult error(int code, String msg)
|
public static AjaxResult error(int code, String msg)
|
||||||
{
|
{
|
||||||
return new AjaxResult(code, msg, null);
|
return new AjaxResult(code, msg, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -215,6 +215,6 @@ public class AjaxResult extends HashMap<String, Object>
|
|||||||
}
|
}
|
||||||
public static AjaxResult unAuth(int code,String msg)
|
public static AjaxResult unAuth(int code,String msg)
|
||||||
{
|
{
|
||||||
return new AjaxResult(HttpStatus.UNAUTHORIZED, msg,null);
|
return new AjaxResult(HttpStatus.UNAUTHORIZED, msg,"");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,11 @@ import com.alibaba.fastjson2.JSONObject;
|
|||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.ruoyi.common.constant.EncryptConstants;
|
import com.ruoyi.common.constant.EncryptConstants;
|
||||||
|
import com.ruoyi.common.constant.InternalForwardConstants;
|
||||||
import com.ruoyi.common.constant.SM4Constants;
|
import com.ruoyi.common.constant.SM4Constants;
|
||||||
import com.ruoyi.common.utils.EncryptHttpServletRequestWrapper;
|
import com.ruoyi.common.utils.EncryptHttpServletRequestWrapper;
|
||||||
import com.ruoyi.common.utils.EncryptHttpServletResponseWrapper;
|
import com.ruoyi.common.utils.EncryptHttpServletResponseWrapper;
|
||||||
|
import com.ruoyi.common.utils.LogUtils;
|
||||||
import com.ruoyi.common.utils.SM4Utils;
|
import com.ruoyi.common.utils.SM4Utils;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
@@ -22,6 +24,7 @@ import java.io.BufferedReader;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.URLDecoder;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -68,8 +71,31 @@ public class RequestWrapperFilter implements Filter {
|
|||||||
}else{
|
}else{
|
||||||
EncryptHttpServletResponseWrapper responseWrapper = new EncryptHttpServletResponseWrapper(httpResponse);
|
EncryptHttpServletResponseWrapper responseWrapper = new EncryptHttpServletResponseWrapper(httpResponse);
|
||||||
String forwardUrl = buildGetRequestURI(httpRequest);
|
String forwardUrl = buildGetRequestURI(httpRequest);
|
||||||
|
|
||||||
|
// 先做输入规范化 + 解码,消除编码/格式绕过
|
||||||
|
String normalizedForwardUrl = normalizePath(forwardUrl);
|
||||||
|
if (normalizedForwardUrl == null) {
|
||||||
|
log.error("非法内部转发:路径格式异常 {}", LogUtils.cleanLog(forwardUrl));
|
||||||
|
httpResponse.sendError(InternalForwardConstants.FORBIDDEN_CODE, InternalForwardConstants.FORBIDDEN_MSG);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 优先拦截敏感路径(前置拦截,避免白名单绕过)
|
||||||
|
if (containsTraversalChars(normalizedForwardUrl) || containsSensitiveDir(normalizedForwardUrl)) {
|
||||||
|
log.error("非法内部转发:包含敏感路径片段 {}", LogUtils.cleanLog(normalizedForwardUrl));
|
||||||
|
httpResponse.sendError(InternalForwardConstants.FORBIDDEN_CODE, InternalForwardConstants.FORBIDDEN_MSG);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 白名单校验(支持全匹配 + 前缀匹配)
|
||||||
|
if (!isInWhitelist(normalizedForwardUrl)) {
|
||||||
|
log.error("非法内部转发:不在白名单内 {}", LogUtils.cleanLog(normalizedForwardUrl));
|
||||||
|
httpResponse.sendError(InternalForwardConstants.FORBIDDEN_CODE, InternalForwardConstants.FORBIDDEN_MSG);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(forwardUrl)) {
|
if (StringUtils.isNotBlank(forwardUrl)) {
|
||||||
log.info("GET请求解密后转发URL:{}", forwardUrl);
|
log.info("GET请求解密后转发URL:{}", LogUtils.cleanLog(forwardUrl));
|
||||||
// 服务器内部转发
|
// 服务器内部转发
|
||||||
request.setAttribute("ENCRYPT_PROCESSED", Boolean.TRUE);
|
request.setAttribute("ENCRYPT_PROCESSED", Boolean.TRUE);
|
||||||
RequestDispatcher dispatcher = request.getRequestDispatcher(forwardUrl);
|
RequestDispatcher dispatcher = request.getRequestDispatcher(forwardUrl);
|
||||||
@@ -158,7 +184,7 @@ public class RequestWrapperFilter implements Filter {
|
|||||||
|
|
||||||
private HttpServletRequest processBodyRequest(HttpServletRequest request) throws IOException {
|
private HttpServletRequest processBodyRequest(HttpServletRequest request) throws IOException {
|
||||||
String body = getRequestBody(request);
|
String body = getRequestBody(request);
|
||||||
log.info("过滤器 - 原始请求体: " + body);
|
log.info("过滤器 - 原始请求体: " + LogUtils.cleanLog(body));
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(body)) {
|
if (StringUtils.isNotBlank(body)) {
|
||||||
try {
|
try {
|
||||||
@@ -178,7 +204,7 @@ public class RequestWrapperFilter implements Filter {
|
|||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("POST请求体解密失败: " + e.getMessage());
|
log.error("POST请求体解密失败: " + LogUtils.cleanLog(e.getMessage()));
|
||||||
// 解密失败时返回原始请求,让业务层处理
|
// 解密失败时返回原始请求,让业务层处理
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
@@ -262,7 +288,72 @@ public class RequestWrapperFilter implements Filter {
|
|||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("GET请求参数解密/拼接失败", e);
|
log.error("GET请求参数解密/拼接失败", e);
|
||||||
return null; // 异常时返回null,走原始请求
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 白名单校验(支持全匹配 + 前缀匹配)
|
||||||
|
*/
|
||||||
|
private boolean isInWhitelist(String path) {
|
||||||
|
for (String white : InternalForwardConstants.INTERNAL_FORWARD_WHITELIST) {
|
||||||
|
if (white.endsWith("*") && path.startsWith(white.substring(0, white.length() - 1))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (path.equals(white)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否包含敏感目录
|
||||||
|
*/
|
||||||
|
private boolean containsSensitiveDir(String path) {
|
||||||
|
String lowerPath = path.toLowerCase();
|
||||||
|
return lowerPath.contains("web-inf")
|
||||||
|
|| lowerPath.contains("meta-inf")
|
||||||
|
|| lowerPath.contains("/config/")
|
||||||
|
|| lowerPath.contains("/resources/")
|
||||||
|
|| lowerPath.contains("/classes/");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否包含路径遍历字符(../、..\ 等)
|
||||||
|
*/
|
||||||
|
private boolean containsTraversalChars(String path) {
|
||||||
|
return path.contains("../") || path.contains("..\\")
|
||||||
|
|| path.contains("%2e%2e%2f") || path.contains("..%2f")
|
||||||
|
|| path.contains("..%5c");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 路径规范化:处理 /./、/../、编码等问题,返回规范化后的路径
|
||||||
|
*/
|
||||||
|
private String normalizePath(String path) {
|
||||||
|
if (StringUtils.isBlank(path)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
String decodedPath = URLDecoder.decode(path, StandardCharsets.UTF_8.name());
|
||||||
|
decodedPath = decodedPath.replace("\\", "/");
|
||||||
|
StringBuilder normalized = new StringBuilder();
|
||||||
|
String[] segments = decodedPath.split("/");
|
||||||
|
for (String seg : segments) {
|
||||||
|
if (seg.equals(".") || seg.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (seg.equals("..")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
normalized.append("/").append(seg);
|
||||||
|
}
|
||||||
|
String result = normalized.length() == 0 ? "/" : normalized.toString();
|
||||||
|
return result;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("路径规范化失败", e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -15,4 +15,8 @@ public class LogUtils
|
|||||||
}
|
}
|
||||||
return "[" + msg.toString() + "]";
|
return "[" + msg.toString() + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String cleanLog(String str) {
|
||||||
|
return str == null ? null : str.replace("\n", "").replace("\r", "");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,7 +143,8 @@ public class ServletUtils
|
|||||||
response.setStatus(200);
|
response.setStatus(200);
|
||||||
response.setContentType("application/json");
|
response.setContentType("application/json");
|
||||||
response.setCharacterEncoding("utf-8");
|
response.setCharacterEncoding("utf-8");
|
||||||
response.getWriter().print(string);
|
//response.getWriter().print(string);
|
||||||
|
response.getWriter().print(escapeHtml(string));
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
@@ -151,6 +152,30 @@ public class ServletUtils
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTML转义(修复XSS漏洞)
|
||||||
|
* @param content
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static String escapeHtml(String content) {
|
||||||
|
if (content == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
StringBuilder out = new StringBuilder();
|
||||||
|
for (int i = 0; i < content.length(); i++) {
|
||||||
|
char c = content.charAt(i);
|
||||||
|
switch (c) {
|
||||||
|
case '<': out.append("<"); break;
|
||||||
|
case '>': out.append(">"); break;
|
||||||
|
case '&': out.append("&"); break;
|
||||||
|
case '"': out.append("""); break;
|
||||||
|
case '\'': out.append("'"); break;
|
||||||
|
default: out.append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out.toString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否是Ajax异步请求
|
* 是否是Ajax异步请求
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -113,7 +113,8 @@ public class FileUploadUtils
|
|||||||
String fileName = extractFilename(file);
|
String fileName = extractFilename(file);
|
||||||
|
|
||||||
String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();
|
String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();
|
||||||
file.transferTo(Paths.get(absPath));
|
File safeFile=new File(absPath).getCanonicalFile();
|
||||||
|
file.transferTo(safeFile);
|
||||||
return getPathFileName(baseDir, fileName);
|
return getPathFileName(baseDir, fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,7 +129,7 @@ public class FileUploadUtils
|
|||||||
|
|
||||||
public static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException
|
public static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException
|
||||||
{
|
{
|
||||||
File desc = new File(uploadDir + File.separator + fileName);
|
File desc = new File(uploadDir + File.separator + fileName).getCanonicalFile();
|
||||||
|
|
||||||
if (!desc.exists())
|
if (!desc.exists())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ public class FileUtils
|
|||||||
FileInputStream fis = null;
|
FileInputStream fis = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
File file = new File(filePath);
|
File file = new File(filePath).getCanonicalFile();
|
||||||
if (!file.exists())
|
if (!file.exists())
|
||||||
{
|
{
|
||||||
throw new FileNotFoundException(filePath);
|
throw new FileNotFoundException(filePath);
|
||||||
@@ -92,7 +92,7 @@ public class FileUtils
|
|||||||
{
|
{
|
||||||
String extension = getFileExtendName(data);
|
String extension = getFileExtendName(data);
|
||||||
pathName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension;
|
pathName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension;
|
||||||
File file = FileUploadUtils.getAbsoluteFile(uploadDir, pathName);
|
File file = FileUploadUtils.getAbsoluteFile(uploadDir, pathName).getCanonicalFile();
|
||||||
fos = new FileOutputStream(file);
|
fos = new FileOutputStream(file);
|
||||||
fos.write(data);
|
fos.write(data);
|
||||||
}
|
}
|
||||||
@@ -111,14 +111,18 @@ public class FileUtils
|
|||||||
*/
|
*/
|
||||||
public static boolean deleteFile(String filePath)
|
public static boolean deleteFile(String filePath)
|
||||||
{
|
{
|
||||||
boolean flag = false;
|
if (filePath == null || filePath.isEmpty()) {
|
||||||
File file = new File(filePath);
|
return false;
|
||||||
// 路径为文件且不为空则进行删除
|
|
||||||
if (file.isFile() && file.exists())
|
|
||||||
{
|
|
||||||
flag = file.delete();
|
|
||||||
}
|
}
|
||||||
return flag;
|
try {
|
||||||
|
File file = new File(filePath).getCanonicalFile();
|
||||||
|
if (file.isFile() && file.exists()) {
|
||||||
|
return file.delete();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -291,7 +295,7 @@ public class FileUtils
|
|||||||
public static File createTempFile(String filePath, byte[] data) throws IOException
|
public static File createTempFile(String filePath, byte[] data) throws IOException
|
||||||
{
|
{
|
||||||
String temp = getTemp() + filePath;
|
String temp = getTemp() + filePath;
|
||||||
File file = new File(temp);
|
File file = new File(temp).getCanonicalFile();;
|
||||||
if (!file.getParentFile().exists())
|
if (!file.getParentFile().exists())
|
||||||
{
|
{
|
||||||
file.getParentFile().mkdirs();
|
file.getParentFile().mkdirs();
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.ruoyi.common.utils.file;
|
package com.ruoyi.common.utils.file;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
@@ -70,6 +71,10 @@ public class ImageUtils
|
|||||||
{
|
{
|
||||||
// 网络地址
|
// 网络地址
|
||||||
URL urlObj = new URL(url);
|
URL urlObj = new URL(url);
|
||||||
|
String protocol = urlObj.getProtocol();
|
||||||
|
if (!"http".equalsIgnoreCase(protocol) && !"https".equalsIgnoreCase(protocol)) {
|
||||||
|
throw new SecurityException("非法请求,仅支持HTTP/HTTPS协议");
|
||||||
|
}
|
||||||
URLConnection urlConnection = urlObj.openConnection();
|
URLConnection urlConnection = urlObj.openConnection();
|
||||||
urlConnection.setConnectTimeout(30 * 1000);
|
urlConnection.setConnectTimeout(30 * 1000);
|
||||||
urlConnection.setReadTimeout(60 * 1000);
|
urlConnection.setReadTimeout(60 * 1000);
|
||||||
@@ -81,7 +86,8 @@ public class ImageUtils
|
|||||||
// 本机地址
|
// 本机地址
|
||||||
String localPath = RuoYiConfig.getProfile();
|
String localPath = RuoYiConfig.getProfile();
|
||||||
String downloadPath = localPath + StringUtils.substringAfter(url, Constants.RESOURCE_PREFIX);
|
String downloadPath = localPath + StringUtils.substringAfter(url, Constants.RESOURCE_PREFIX);
|
||||||
in = new FileInputStream(downloadPath);
|
File safeFile = new File(downloadPath).getCanonicalFile();
|
||||||
|
in = new FileInputStream(safeFile);
|
||||||
}
|
}
|
||||||
return IOUtils.toByteArray(in);
|
return IOUtils.toByteArray(in);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,8 +23,13 @@ public class HttpHelper
|
|||||||
{
|
{
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
BufferedReader reader = null;
|
BufferedReader reader = null;
|
||||||
try (InputStream inputStream = request.getInputStream())
|
try
|
||||||
{
|
{
|
||||||
|
InputStream inputStream = request.getInputStream();
|
||||||
|
//修复漏洞
|
||||||
|
if (inputStream == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
|
reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
|
||||||
String line = "";
|
String line = "";
|
||||||
while ((line = reader.readLine()) != null)
|
while ((line = reader.readLine()) != null)
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import javax.net.ssl.SSLContext;
|
|||||||
import javax.net.ssl.SSLSession;
|
import javax.net.ssl.SSLSession;
|
||||||
import javax.net.ssl.TrustManager;
|
import javax.net.ssl.TrustManager;
|
||||||
import javax.net.ssl.X509TrustManager;
|
import javax.net.ssl.X509TrustManager;
|
||||||
|
|
||||||
|
import com.ruoyi.common.utils.LogUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import com.ruoyi.common.constant.Constants;
|
import com.ruoyi.common.constant.Constants;
|
||||||
@@ -62,8 +64,12 @@ public class HttpUtils
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
String urlNameString = StringUtils.isNotBlank(param) ? url + "?" + param : url;
|
String urlNameString = StringUtils.isNotBlank(param) ? url + "?" + param : url;
|
||||||
log.info("sendGet - {}", urlNameString);
|
log.info("sendGet - {}", LogUtils.cleanLog(urlNameString));
|
||||||
URL realUrl = new URL(urlNameString);
|
URL realUrl = new URL(urlNameString);
|
||||||
|
String protocol = realUrl.getProtocol();
|
||||||
|
if (!"http".equalsIgnoreCase(protocol) && !"https".equalsIgnoreCase(protocol)) {
|
||||||
|
throw new SecurityException("非法请求,仅支持HTTP/HTTPS协议");
|
||||||
|
}
|
||||||
URLConnection connection = realUrl.openConnection();
|
URLConnection connection = realUrl.openConnection();
|
||||||
connection.setRequestProperty("accept", "*/*");
|
connection.setRequestProperty("accept", "*/*");
|
||||||
connection.setRequestProperty("connection", "Keep-Alive");
|
connection.setRequestProperty("connection", "Keep-Alive");
|
||||||
@@ -79,19 +85,19 @@ public class HttpUtils
|
|||||||
}
|
}
|
||||||
catch (ConnectException e)
|
catch (ConnectException e)
|
||||||
{
|
{
|
||||||
log.error("调用HttpUtils.sendGet ConnectException, url=" + url + ",param=" + param, e);
|
log.error("调用HttpUtils.sendGet ConnectException, url=" + LogUtils.cleanLog(url) + ",param=" + LogUtils.cleanLog(param), e);
|
||||||
}
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
log.error("调用HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" + param, e);
|
log.error("调用HttpUtils.sendGet SocketTimeoutException, url=" + LogUtils.cleanLog(url) + ",param=" + LogUtils.cleanLog(param), e);
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
log.error("调用HttpUtils.sendGet IOException, url=" + url + ",param=" + param, e);
|
log.error("调用HttpUtils.sendGet IOException, url=" + LogUtils.cleanLog(url) + ",param=" + LogUtils.cleanLog(param), e);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
log.error("调用HttpsUtil.sendGet Exception, url=" + url + ",param=" + param, e);
|
log.error("调用HttpsUtil.sendGet Exception, url=" + LogUtils.cleanLog(url) + ",param=" + LogUtils.cleanLog(param), e);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -104,7 +110,7 @@ public class HttpUtils
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
|
log.error("调用in.close Exception, url=" + LogUtils.cleanLog(url) + ",param=" + LogUtils.cleanLog(param), ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result.toString();
|
return result.toString();
|
||||||
@@ -124,8 +130,12 @@ public class HttpUtils
|
|||||||
StringBuilder result = new StringBuilder();
|
StringBuilder result = new StringBuilder();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
log.info("sendPost - {}", url);
|
log.info("sendPost - {}", LogUtils.cleanLog(url));
|
||||||
URL realUrl = new URL(url);
|
URL realUrl = new URL(url);
|
||||||
|
String protocol = realUrl.getProtocol();
|
||||||
|
if (!"http".equalsIgnoreCase(protocol) && !"https".equalsIgnoreCase(protocol)) {
|
||||||
|
throw new SecurityException("非法请求,仅支持HTTP/HTTPS协议");
|
||||||
|
}
|
||||||
URLConnection conn = realUrl.openConnection();
|
URLConnection conn = realUrl.openConnection();
|
||||||
conn.setRequestProperty("accept", "*/*");
|
conn.setRequestProperty("accept", "*/*");
|
||||||
conn.setRequestProperty("connection", "Keep-Alive");
|
conn.setRequestProperty("connection", "Keep-Alive");
|
||||||
@@ -147,19 +157,19 @@ public class HttpUtils
|
|||||||
}
|
}
|
||||||
catch (ConnectException e)
|
catch (ConnectException e)
|
||||||
{
|
{
|
||||||
log.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e);
|
log.error("调用HttpUtils.sendPost ConnectException, url=" + LogUtils.cleanLog(url) + ",param=" + LogUtils.cleanLog(param), e);
|
||||||
}
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e);
|
log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + LogUtils.cleanLog(url) + ",param=" + LogUtils.cleanLog(param), e);
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
log.error("调用HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e);
|
log.error("调用HttpUtils.sendPost IOException, url=" + LogUtils.cleanLog(url) + ",param=" + LogUtils.cleanLog(param), e);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
log.error("调用HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e);
|
log.error("调用HttpsUtil.sendPost Exception, url=" + LogUtils.cleanLog(url) + ",param=" + LogUtils.cleanLog(param), e);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -176,7 +186,7 @@ public class HttpUtils
|
|||||||
}
|
}
|
||||||
catch (IOException ex)
|
catch (IOException ex)
|
||||||
{
|
{
|
||||||
log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
|
log.error("调用in.close Exception, url=" + LogUtils.cleanLog(url) + ",param=" + LogUtils.cleanLog(param), ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result.toString();
|
return result.toString();
|
||||||
@@ -188,10 +198,14 @@ public class HttpUtils
|
|||||||
String urlNameString = url + "?" + param;
|
String urlNameString = url + "?" + param;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
log.info("sendSSLPost - {}", urlNameString);
|
log.info("sendSSLPost - {}", LogUtils.cleanLog(urlNameString));
|
||||||
SSLContext sc = SSLContext.getInstance("SSL");
|
SSLContext sc = SSLContext.getInstance("SSL");
|
||||||
sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom());
|
sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom());
|
||||||
URL console = new URL(urlNameString);
|
URL console = new URL(urlNameString);
|
||||||
|
String protocol = console.getProtocol();
|
||||||
|
if (!"http".equalsIgnoreCase(protocol) && !"https".equalsIgnoreCase(protocol)) {
|
||||||
|
throw new SecurityException("非法请求,仅支持HTTP/HTTPS协议");
|
||||||
|
}
|
||||||
HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();
|
HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();
|
||||||
conn.setRequestProperty("accept", "*/*");
|
conn.setRequestProperty("accept", "*/*");
|
||||||
conn.setRequestProperty("connection", "Keep-Alive");
|
conn.setRequestProperty("connection", "Keep-Alive");
|
||||||
@@ -220,19 +234,19 @@ public class HttpUtils
|
|||||||
}
|
}
|
||||||
catch (ConnectException e)
|
catch (ConnectException e)
|
||||||
{
|
{
|
||||||
log.error("调用HttpUtils.sendSSLPost ConnectException, url=" + url + ",param=" + param, e);
|
log.error("调用HttpUtils.sendSSLPost ConnectException, url=" + LogUtils.cleanLog(url) + ",param=" + LogUtils.cleanLog(param), e);
|
||||||
}
|
}
|
||||||
catch (SocketTimeoutException e)
|
catch (SocketTimeoutException e)
|
||||||
{
|
{
|
||||||
log.error("调用HttpUtils.sendSSLPost SocketTimeoutException, url=" + url + ",param=" + param, e);
|
log.error("调用HttpUtils.sendSSLPost SocketTimeoutException, url=" + LogUtils.cleanLog(url) + ",param=" + LogUtils.cleanLog(param), e);
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
log.error("调用HttpUtils.sendSSLPost IOException, url=" + url + ",param=" + param, e);
|
log.error("调用HttpUtils.sendSSLPost IOException, url=" + LogUtils.cleanLog(url) + ",param=" + LogUtils.cleanLog(param), e);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
log.error("调用HttpsUtil.sendSSLPost Exception, url=" + url + ",param=" + param, e);
|
log.error("调用HttpsUtil.sendSSLPost Exception, url=" + LogUtils.cleanLog(url) + ",param=" + LogUtils.cleanLog(param), e);
|
||||||
}
|
}
|
||||||
return result.toString();
|
return result.toString();
|
||||||
}
|
}
|
||||||
@@ -246,6 +260,11 @@ public class HttpUtils
|
|||||||
String result = null;
|
String result = null;
|
||||||
try {
|
try {
|
||||||
URL url = new URL(httpUrl);
|
URL url = new URL(httpUrl);
|
||||||
|
//代码测试添加
|
||||||
|
String protocol = url.getProtocol();
|
||||||
|
if (!"http".equalsIgnoreCase(protocol) && !"https".equalsIgnoreCase(protocol)) {
|
||||||
|
throw new SecurityException("非法请求,仅支持HTTP/HTTPS协议");
|
||||||
|
}
|
||||||
// 通过远程url连接对象打开连接
|
// 通过远程url连接对象打开连接
|
||||||
connection = (HttpURLConnection) url.openConnection();
|
connection = (HttpURLConnection) url.openConnection();
|
||||||
// 设置连接请求方式
|
// 设置连接请求方式
|
||||||
|
|||||||
@@ -644,13 +644,14 @@ public class ExcelUtil<T>
|
|||||||
{
|
{
|
||||||
writeSheet();
|
writeSheet();
|
||||||
String filename = encodingFilename(sheetName);
|
String filename = encodingFilename(sheetName);
|
||||||
out = new FileOutputStream(getAbsoluteFile(filename));
|
|
||||||
|
File file = new File(getAbsoluteFile(filename)).getCanonicalFile();
|
||||||
|
out = new FileOutputStream(file);
|
||||||
wb.write(out);
|
wb.write(out);
|
||||||
return AjaxResult.success(filename);
|
return AjaxResult.success(filename);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
log.error("导出Excel异常{}", e.getMessage());
|
|
||||||
throw new UtilException("导出Excel失败,请联系网站管理员!");
|
throw new UtilException("导出Excel失败,请联系网站管理员!");
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@@ -1410,11 +1411,15 @@ public class ExcelUtil<T>
|
|||||||
public String getAbsoluteFile(String filename)
|
public String getAbsoluteFile(String filename)
|
||||||
{
|
{
|
||||||
String downloadPath = RuoYiConfig.getDownloadPath() + filename;
|
String downloadPath = RuoYiConfig.getDownloadPath() + filename;
|
||||||
File desc = new File(downloadPath);
|
try {
|
||||||
|
File desc = new File(downloadPath).getCanonicalFile();
|
||||||
if (!desc.getParentFile().exists())
|
if (!desc.getParentFile().exists())
|
||||||
{
|
{
|
||||||
desc.getParentFile().mkdirs();
|
desc.getParentFile().mkdirs();
|
||||||
}
|
}
|
||||||
|
}catch (Exception e){
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
return downloadPath;
|
return downloadPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1515,10 +1520,13 @@ public class ExcelUtil<T>
|
|||||||
{
|
{
|
||||||
Excels attrs = field.getAnnotation(Excels.class);
|
Excels attrs = field.getAnnotation(Excels.class);
|
||||||
Excel[] excels = attrs.value();
|
Excel[] excels = attrs.value();
|
||||||
|
|
||||||
|
if (excels != null) {
|
||||||
for (Excel attr : excels)
|
for (Excel attr : excels)
|
||||||
{
|
{
|
||||||
if (!ArrayUtils.contains(this.excludeFields, field.getName() + "." + attr.targetAttr())
|
if (attr != null
|
||||||
&& (attr != null && (attr.type() == Type.ALL || attr.type() == type)))
|
&& !ArrayUtils.contains(this.excludeFields, field.getName() + "." + attr.targetAttr())
|
||||||
|
&& (attr.type() == Type.ALL || attr.type() == type))
|
||||||
{
|
{
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
fields.add(new Object[] { field, attr });
|
fields.add(new Object[] { field, attr });
|
||||||
@@ -1527,6 +1535,7 @@ public class ExcelUtil<T>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return fields;
|
return fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,66 +2,109 @@ package com.ruoyi.common.utils.sign;
|
|||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Md5加密方法
|
* 哈希加密工具类
|
||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
public class Md5Utils
|
public class Md5Utils
|
||||||
{
|
{
|
||||||
private static final Logger log = LoggerFactory.getLogger(Md5Utils.class);
|
private static final Logger log = LoggerFactory.getLogger(Md5Utils.class);
|
||||||
|
// 升级算法为SHA-256(更安全,避免MD5碰撞风险)
|
||||||
|
private static final String HASH_ALGORITHM = "SHA-256";
|
||||||
|
// 可选:默认盐值(建议从配置文件读取,此处仅示例)
|
||||||
|
private static final String DEFAULT_SALT = "ruoyi@2025#secureSalt";
|
||||||
|
|
||||||
private static byte[] md5(String s)
|
/**
|
||||||
|
* 核心加密方法:生成SHA-256哈希字节数组
|
||||||
|
* 修复点:空值校验、编码规范、精准异常捕获、避免返回null
|
||||||
|
*/
|
||||||
|
private static byte[] sha256(String s)
|
||||||
{
|
{
|
||||||
MessageDigest algorithm;
|
// 空值校验:避免后续NPE
|
||||||
try
|
if (s == null) {
|
||||||
{
|
log.warn("SHA-256加密入参为null,返回空字节数组");
|
||||||
algorithm = MessageDigest.getInstance("MD5");
|
return new byte[0];
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
MessageDigest algorithm = MessageDigest.getInstance(HASH_ALGORITHM);
|
||||||
algorithm.reset();
|
algorithm.reset();
|
||||||
algorithm.update(s.getBytes("UTF-8"));
|
// 替换硬编码字符串为StandardCharsets常量,避免UnsupportedEncodingException
|
||||||
byte[] messageDigest = algorithm.digest();
|
algorithm.update(s.getBytes(StandardCharsets.UTF_8));
|
||||||
return messageDigest;
|
return algorithm.digest();
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
// 精准捕获算法不存在异常,而非泛化Exception
|
||||||
|
log.error("SHA-256算法不存在(JDK环境异常)", e);
|
||||||
|
return new byte[0];
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("SHA-256加密过程异常", e);
|
||||||
|
return new byte[0];
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
log.error("MD5 Error...", e);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字节数组转十六进制字符串
|
||||||
|
* 修复点:避免返回null、优化转换效率、统一小写(可按需改大写)
|
||||||
|
*/
|
||||||
private static final String toHex(byte hash[])
|
private static final String toHex(byte hash[])
|
||||||
{
|
{
|
||||||
if (hash == null)
|
// 空值/空数组校验:返回空字符串而非null
|
||||||
{
|
if (hash == null || hash.length == 0) {
|
||||||
return null;
|
return "";
|
||||||
}
|
}
|
||||||
StringBuffer buf = new StringBuffer(hash.length * 2);
|
StringBuffer buf = new StringBuffer(hash.length * 2);
|
||||||
int i;
|
for (byte b : hash) {
|
||||||
|
int val = b & 0xff;
|
||||||
for (i = 0; i < hash.length; i++)
|
if (val < 0x10) {
|
||||||
{
|
|
||||||
if ((hash[i] & 0xff) < 0x10)
|
|
||||||
{
|
|
||||||
buf.append("0");
|
buf.append("0");
|
||||||
}
|
}
|
||||||
buf.append(Long.toString(hash[i] & 0xff, 16));
|
// 替换Long.toString为Integer.toHexString,提升效率
|
||||||
|
buf.append(Integer.toHexString(val));
|
||||||
}
|
}
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 兼容原有业务的哈希加密方法(核心对外方法)
|
||||||
|
* 修复点:空值防御、异常兜底逻辑优化、避免NPE
|
||||||
|
*/
|
||||||
public static String hash(String s)
|
public static String hash(String s)
|
||||||
{
|
{
|
||||||
try
|
try {
|
||||||
{
|
// 先加密生成字节数组,再转十六进制
|
||||||
return new String(toHex(md5(s)).getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8);
|
byte[] digest = sha256(s);
|
||||||
|
String hexStr = toHex(digest);
|
||||||
|
// 编码转换:使用StandardCharsets避免异常,且无需额外转换(hexStr本身是ASCII)
|
||||||
|
return hexStr;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("SHA-256加密/编码异常", e);
|
||||||
|
return s == null ? "" : "";
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
log.error("not supported charset...{}", e);
|
|
||||||
return s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 增强版:带盐值的SHA-256加密(防彩虹表攻击,推荐业务使用)
|
||||||
|
* @param s 原始字符串
|
||||||
|
* @param salt 自定义盐值(建议用用户唯一标识+固定盐值)
|
||||||
|
* @return 加密后的十六进制字符串
|
||||||
|
*/
|
||||||
|
public static String hashWithSalt(String s, String salt) {
|
||||||
|
if (salt == null) {
|
||||||
|
salt = "";
|
||||||
|
}
|
||||||
|
// 盐值拼接(可按需调整为前缀/中间拼接)
|
||||||
|
String target = s + salt;
|
||||||
|
return hash(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 便捷方法:使用默认盐值加密
|
||||||
|
*/
|
||||||
|
public static String hashWithDefaultSalt(String s) {
|
||||||
|
return hashWithSalt(s, DEFAULT_SALT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,7 +116,7 @@ public final class UUID implements java.io.Serializable, Comparable<UUID>
|
|||||||
MessageDigest md;
|
MessageDigest md;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
md = MessageDigest.getInstance("MD5");
|
md = MessageDigest.getInstance("SHA-1");
|
||||||
}
|
}
|
||||||
catch (NoSuchAlgorithmException nsae)
|
catch (NoSuchAlgorithmException nsae)
|
||||||
{
|
{
|
||||||
@@ -463,7 +463,7 @@ public final class UUID implements java.io.Serializable, Comparable<UUID>
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return SecureRandom.getInstance("SHA1PRNG");
|
return SecureRandom.getInstanceStrong();
|
||||||
}
|
}
|
||||||
catch (NoSuchAlgorithmException e)
|
catch (NoSuchAlgorithmException e)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user