修改漏洞问题-pc端已测试完成

This commit is contained in:
sh
2026-04-11 13:05:08 +08:00
parent 8b2ae55baf
commit 62e86f24c9
25 changed files with 439 additions and 126 deletions

View File

@@ -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 = "禁止访问:非法内部转发路径";
}

View File

@@ -87,7 +87,7 @@ public class AjaxResult extends HashMap<String, Object>
*/
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)
{
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)
{
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)
{
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)
{
return new AjaxResult(HttpStatus.UNAUTHORIZED, msg,null);
return new AjaxResult(HttpStatus.UNAUTHORIZED, msg,"");
}
}

View File

@@ -4,9 +4,11 @@ import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.constant.EncryptConstants;
import com.ruoyi.common.constant.InternalForwardConstants;
import com.ruoyi.common.constant.SM4Constants;
import com.ruoyi.common.utils.EncryptHttpServletRequestWrapper;
import com.ruoyi.common.utils.EncryptHttpServletResponseWrapper;
import com.ruoyi.common.utils.LogUtils;
import com.ruoyi.common.utils.SM4Utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
@@ -22,6 +24,7 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
@@ -68,8 +71,31 @@ public class RequestWrapperFilter implements Filter {
}else{
EncryptHttpServletResponseWrapper responseWrapper = new EncryptHttpServletResponseWrapper(httpResponse);
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)) {
log.info("GET请求解密后转发URL{}", forwardUrl);
log.info("GET请求解密后转发URL{}", LogUtils.cleanLog(forwardUrl));
// 服务器内部转发
request.setAttribute("ENCRYPT_PROCESSED", Boolean.TRUE);
RequestDispatcher dispatcher = request.getRequestDispatcher(forwardUrl);
@@ -158,7 +184,7 @@ public class RequestWrapperFilter implements Filter {
private HttpServletRequest processBodyRequest(HttpServletRequest request) throws IOException {
String body = getRequestBody(request);
log.info("过滤器 - 原始请求体: " + body);
log.info("过滤器 - 原始请求体: " + LogUtils.cleanLog(body));
if (StringUtils.isNotBlank(body)) {
try {
@@ -178,7 +204,7 @@ public class RequestWrapperFilter implements Filter {
return request;
}
} catch (Exception e) {
log.error("POST请求体解密失败: " + e.getMessage());
log.error("POST请求体解密失败: " + LogUtils.cleanLog(e.getMessage()));
// 解密失败时返回原始请求,让业务层处理
return request;
}
@@ -262,7 +288,72 @@ public class RequestWrapperFilter implements Filter {
} catch (Exception 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;
}
}
}

View File

@@ -15,4 +15,8 @@ public class LogUtils
}
return "[" + msg.toString() + "]";
}
public static String cleanLog(String str) {
return str == null ? null : str.replace("\n", "").replace("\r", "");
}
}

View File

@@ -143,7 +143,8 @@ public class ServletUtils
response.setStatus(200);
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
response.getWriter().print(string);
//response.getWriter().print(string);
response.getWriter().print(escapeHtml(string));
}
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("&lt;"); break;
case '>': out.append("&gt;"); break;
case '&': out.append("&amp;"); break;
case '"': out.append("&quot;"); break;
case '\'': out.append("&#39;"); break;
default: out.append(c);
}
}
return out.toString();
}
/**
* 是否是Ajax异步请求
*

View File

@@ -113,7 +113,8 @@ public class FileUploadUtils
String fileName = extractFilename(file);
String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();
file.transferTo(Paths.get(absPath));
File safeFile=new File(absPath).getCanonicalFile();
file.transferTo(safeFile);
return getPathFileName(baseDir, fileName);
}
@@ -128,7 +129,7 @@ public class FileUploadUtils
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())
{

View File

@@ -40,7 +40,7 @@ public class FileUtils
FileInputStream fis = null;
try
{
File file = new File(filePath);
File file = new File(filePath).getCanonicalFile();
if (!file.exists())
{
throw new FileNotFoundException(filePath);
@@ -92,7 +92,7 @@ public class FileUtils
{
String extension = getFileExtendName(data);
pathName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension;
File file = FileUploadUtils.getAbsoluteFile(uploadDir, pathName);
File file = FileUploadUtils.getAbsoluteFile(uploadDir, pathName).getCanonicalFile();
fos = new FileOutputStream(file);
fos.write(data);
}
@@ -111,14 +111,18 @@ public class FileUtils
*/
public static boolean deleteFile(String filePath)
{
boolean flag = false;
File file = new File(filePath);
// 路径为文件且不为空则进行删除
if (file.isFile() && file.exists())
{
flag = file.delete();
if (filePath == null || filePath.isEmpty()) {
return false;
}
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
{
String temp = getTemp() + filePath;
File file = new File(temp);
File file = new File(temp).getCanonicalFile();;
if (!file.getParentFile().exists())
{
file.getParentFile().mkdirs();

View File

@@ -1,6 +1,7 @@
package com.ruoyi.common.utils.file;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URL;
@@ -70,6 +71,10 @@ public class ImageUtils
{
// 网络地址
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.setConnectTimeout(30 * 1000);
urlConnection.setReadTimeout(60 * 1000);
@@ -81,7 +86,8 @@ public class ImageUtils
// 本机地址
String localPath = RuoYiConfig.getProfile();
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);
}

View File

@@ -23,8 +23,13 @@ public class HttpHelper
{
StringBuilder sb = new StringBuilder();
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));
String line = "";
while ((line = reader.readLine()) != null)

View File

@@ -10,6 +10,8 @@ import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import com.ruoyi.common.utils.LogUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ruoyi.common.constant.Constants;
@@ -62,8 +64,12 @@ public class HttpUtils
try
{
String urlNameString = StringUtils.isNotBlank(param) ? url + "?" + param : url;
log.info("sendGet - {}", urlNameString);
log.info("sendGet - {}", LogUtils.cleanLog(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();
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
@@ -79,19 +85,19 @@ public class HttpUtils
}
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)
{
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)
{
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)
{
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
{
@@ -104,7 +110,7 @@ public class HttpUtils
}
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();
@@ -124,8 +130,12 @@ public class HttpUtils
StringBuilder result = new StringBuilder();
try
{
log.info("sendPost - {}", url);
log.info("sendPost - {}", LogUtils.cleanLog(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();
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
@@ -147,19 +157,19 @@ public class HttpUtils
}
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)
{
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)
{
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)
{
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
{
@@ -176,7 +186,7 @@ public class HttpUtils
}
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();
@@ -188,10 +198,14 @@ public class HttpUtils
String urlNameString = url + "?" + param;
try
{
log.info("sendSSLPost - {}", urlNameString);
log.info("sendSSLPost - {}", LogUtils.cleanLog(urlNameString));
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom());
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();
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
@@ -220,19 +234,19 @@ public class HttpUtils
}
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)
{
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)
{
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)
{
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();
}
@@ -246,6 +260,11 @@ public class HttpUtils
String result = null;
try {
URL url = new URL(httpUrl);
//代码测试添加
String protocol = url.getProtocol();
if (!"http".equalsIgnoreCase(protocol) && !"https".equalsIgnoreCase(protocol)) {
throw new SecurityException("非法请求仅支持HTTP/HTTPS协议");
}
// 通过远程url连接对象打开连接
connection = (HttpURLConnection) url.openConnection();
// 设置连接请求方式

View File

@@ -644,13 +644,14 @@ public class ExcelUtil<T>
{
writeSheet();
String filename = encodingFilename(sheetName);
out = new FileOutputStream(getAbsoluteFile(filename));
File file = new File(getAbsoluteFile(filename)).getCanonicalFile();
out = new FileOutputStream(file);
wb.write(out);
return AjaxResult.success(filename);
}
catch (Exception e)
{
log.error("导出Excel异常{}", e.getMessage());
throw new UtilException("导出Excel失败请联系网站管理员");
}
finally
@@ -1410,10 +1411,14 @@ public class ExcelUtil<T>
public String getAbsoluteFile(String filename)
{
String downloadPath = RuoYiConfig.getDownloadPath() + filename;
File desc = new File(downloadPath);
if (!desc.getParentFile().exists())
{
desc.getParentFile().mkdirs();
try {
File desc = new File(downloadPath).getCanonicalFile();
if (!desc.getParentFile().exists())
{
desc.getParentFile().mkdirs();
}
}catch (Exception e){
e.printStackTrace();
}
return downloadPath;
}
@@ -1515,13 +1520,17 @@ public class ExcelUtil<T>
{
Excels attrs = field.getAnnotation(Excels.class);
Excel[] excels = attrs.value();
for (Excel attr : excels)
{
if (!ArrayUtils.contains(this.excludeFields, field.getName() + "." + attr.targetAttr())
&& (attr != null && (attr.type() == Type.ALL || attr.type() == type)))
if (excels != null) {
for (Excel attr : excels)
{
field.setAccessible(true);
fields.add(new Object[] { field, attr });
if (attr != null
&& !ArrayUtils.contains(this.excludeFields, field.getName() + "." + attr.targetAttr())
&& (attr.type() == Type.ALL || attr.type() == type))
{
field.setAccessible(true);
fields.add(new Object[] { field, attr });
}
}
}
}

View File

@@ -2,66 +2,109 @@ package com.ruoyi.common.utils.sign;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Md5加密方法
*
* 哈希加密工具类
*
* @author ruoyi
*/
public class Md5Utils
{
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;
try
{
algorithm = MessageDigest.getInstance("MD5");
// 空值校验避免后续NPE
if (s == null) {
log.warn("SHA-256加密入参为null返回空字节数组");
return new byte[0];
}
try {
MessageDigest algorithm = MessageDigest.getInstance(HASH_ALGORITHM);
algorithm.reset();
algorithm.update(s.getBytes("UTF-8"));
byte[] messageDigest = algorithm.digest();
return messageDigest;
// 替换硬编码字符串为StandardCharsets常量避免UnsupportedEncodingException
algorithm.update(s.getBytes(StandardCharsets.UTF_8));
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[])
{
if (hash == null)
{
return null;
// 空值/空数组校验:返回空字符串而非null
if (hash == null || hash.length == 0) {
return "";
}
StringBuffer buf = new StringBuffer(hash.length * 2);
int i;
for (i = 0; i < hash.length; i++)
{
if ((hash[i] & 0xff) < 0x10)
{
for (byte b : hash) {
int val = b & 0xff;
if (val < 0x10) {
buf.append("0");
}
buf.append(Long.toString(hash[i] & 0xff, 16));
// 替换Long.toString为Integer.toHexString提升效率
buf.append(Integer.toHexString(val));
}
return buf.toString();
}
/**
* 兼容原有业务的哈希加密方法(核心对外方法)
* 修复点空值防御、异常兜底逻辑优化、避免NPE
*/
public static String hash(String s)
{
try
{
return new String(toHex(md5(s)).getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8);
}
catch (Exception e)
{
log.error("not supported charset...{}", e);
return s;
try {
// 先加密生成字节数组,再转十六进制
byte[] digest = sha256(s);
String hexStr = toHex(digest);
// 编码转换使用StandardCharsets避免异常且无需额外转换hexStr本身是ASCII
return hexStr;
} catch (Exception e) {
log.error("SHA-256加密/编码异常", e);
return s == null ? "" : "";
}
}
}
/**
* 增强版带盐值的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);
}
}

View File

@@ -116,7 +116,7 @@ public final class UUID implements java.io.Serializable, Comparable<UUID>
MessageDigest md;
try
{
md = MessageDigest.getInstance("MD5");
md = MessageDigest.getInstance("SHA-1");
}
catch (NoSuchAlgorithmException nsae)
{
@@ -463,7 +463,7 @@ public final class UUID implements java.io.Serializable, Comparable<UUID>
{
try
{
return SecureRandom.getInstance("SHA1PRNG");
return SecureRandom.getInstanceStrong();
}
catch (NoSuchAlgorithmException e)
{