安全漏洞和渗透修复

This commit is contained in:
马三炮 2025-08-27 10:24:12 +08:00
parent c79ade0cb8
commit ca4a805c5d
11 changed files with 5756 additions and 1517 deletions

View File

@ -35,6 +35,11 @@ public class SysLogController {
*/
@RequestMapping(value = "/queryByPage")
public String queryByPage(SysLogs sysLogs, @RequestParam("page") Integer page, @RequestParam("limit") Integer pageSize) {
String username = sysLogs.getUsername();
// 用正则匹配是否包含非法字符若匹配到则说明有非法字符
if (username.matches(".*[^a-zA-Z0-9\u4e00-\u9fa5-].*")) {
return "{\"code\":1 , \"msg\":\"操作人仅允许输入中英文、数字和连字符\"}";
}
int count = sysLogDao.count(sysLogs);
page = (page - 1) * pageSize;
List<SysLogs> list = this.sysLogDao.queryAllByLimit(sysLogs, page, pageSize);

View File

@ -16,10 +16,11 @@ import org.springframework.security.web.authentication.AuthenticationFailureHand
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.web.cors.CorsConfigurationSource;
/**
* spring security配置
*
*
*/
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class BnsSecurityConfig extends WebSecurityConfigurerAdapter {
@ -37,6 +38,9 @@ public class BnsSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private TokenFilter tokenFilter;
@Autowired
private CorsConfigurationSource corsConfigurationSource;
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
@ -45,7 +49,8 @@ public class BnsSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
// 使用新的跨域配置
http.cors(cors -> cors.configurationSource(corsConfigurationSource));
// 基于token所以不需要session
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

View File

@ -0,0 +1,89 @@
package com.bonus.boot.manager.manager.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.Arrays;
import java.util.List;
/**
* 跨域配置类
* 解决前后端不分离项目的跨域问题
*/
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Value("${cors.allowed-origins}")
private String allowedOrigins;
@Value("${cors.allowed-methods}")
private String allowedMethods;
@Value("${cors.allowed-headers}")
private String allowedHeaders;
@Value("${cors.allow-credentials}")
private boolean allowCredentials;
@Value("${cors.max-age}")
private long maxAge;
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns(getAllowedOriginPatterns().toArray(new String[0]))
.allowedMethods(getAllowedMethodArray())
.allowedHeaders(getAllowedHeaderArray())
.allowCredentials(allowCredentials)
.maxAge(maxAge)
.exposedHeaders("Content-Length", "Content-Type", "Token", "Authorization");
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOriginPatterns(getAllowedOriginPatterns());
configuration.setAllowedMethods(Arrays.asList(getAllowedMethodArray()));
configuration.setAllowedHeaders(Arrays.asList(getAllowedHeaderArray()));
configuration.setExposedHeaders(Arrays.asList("Content-Length", "Content-Type", "Token", "Authorization"));
configuration.setAllowCredentials(allowCredentials);
configuration.setMaxAge(maxAge);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
// 统一仅注册一套白名单策略避免出现*
source.registerCorsConfiguration("/**", configuration);
return source;
}
private List<String> getAllowedOriginPatterns() {
if (allowedOrigins == null || allowedOrigins.trim().isEmpty()) {
return Arrays.asList(
"http://localhost:*",
"http://127.0.0.1:*",
"http://192.168.*.*:*",
"http://10.*.*.*:*"
);
}
return Arrays.asList(allowedOrigins.split(","));
}
private String[] getAllowedMethodArray() {
if (allowedMethods == null || allowedMethods.trim().isEmpty()) {
return new String[]{"GET", "POST", "PUT", "DELETE", "OPTIONS"};
}
return allowedMethods.split(",");
}
private String[] getAllowedHeaderArray() {
if (allowedHeaders == null || allowedHeaders.trim().isEmpty()) {
return new String[]{"Content-Type", "X-Requested-With", "Token", "Authorization", "X-Custom-Header"};
}
return allowedHeaders.split(",");
}
}

View File

@ -0,0 +1,71 @@
package com.bonus.boot.manager.manager.config;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 额外的安全头过滤器
* 用于设置更多的安全相关头信息
*/
@Component
@Order(2)
public class SecurityHeadersFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// 设置额外的安全头
setAdditionalSecurityHeaders(httpRequest, httpResponse);
chain.doFilter(request, response);
}
private void setAdditionalSecurityHeaders(HttpServletRequest request, HttpServletResponse response) {
// 1) 缓存控制
response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0");
response.setHeader("Pragma", "no-cache");
response.setHeader("Expires", "0");
// 2) IE下载策略
response.setHeader("X-Download-Options", "noopen");
// 3) 跨域策略条件化设置
if (isPotentiallyTrustworthy(request)) {
response.setHeader("Cross-Origin-Opener-Policy", "same-origin");
response.setHeader("Cross-Origin-Resource-Policy", "same-origin");
response.setHeader("Cross-Origin-Embedder-Policy", "require-corp");
} else {
response.setHeader("Cross-Origin-Opener-Policy", "");
response.setHeader("Cross-Origin-Resource-Policy", "");
response.setHeader("Cross-Origin-Embedder-Policy", "");
}
// 4) 不再设置已废弃的 Feature-Policy避免与 Permissions-Policy 冲突
// Permissions-Policy 已在 CspFilter 中统一设置
}
private boolean isPotentiallyTrustworthy(HttpServletRequest request) {
boolean isSecure = request.isSecure();
String forwardedProto = request.getHeader("X-Forwarded-Proto");
if (!isSecure && forwardedProto != null) {
isSecure = "https".equalsIgnoreCase(forwardedProto);
}
String host = request.getServerName();
boolean isLocalhost = "localhost".equalsIgnoreCase(host) || "127.0.0.1".equals(host);
return isSecure || isLocalhost;
}
@Override
public void destroy() {
// 清理资源
}
}

View File

@ -19,10 +19,10 @@ public class WebMvcConfig implements WebMvcConfigurer {
/**
* 跨域支持
*
*
* @return
*/
@Bean
/*@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
@ -30,11 +30,11 @@ public class WebMvcConfig implements WebMvcConfigurer {
registry.addMapping("/**").allowedMethods("*");
}
};
}
}*/
/**
* datatable分页解析
*
*
* @return
*/
@Bean

View File

@ -119,7 +119,10 @@ public class UserController {
@ApiOperation(value = "当前登录用户")
@GetMapping("/current")
public SysUser currentUser() {
return UserUtil.getLoginUser();
//置空password
SysUser sysUser = UserUtil.getLoginUser();
sysUser.setPassword(null);
return sysUser;
}
@GetMapping("/getTokenKey")
@ -155,7 +158,7 @@ public class UserController {
}
/**-------------------------------------------以上为老代码,以下为layui新页面所使用的方法-----------------------------------------------------------------*/
@LogAnnotation
@PostMapping("getMsgContent")
@ApiOperation(value = "用户管理-列表")

View File

@ -2,8 +2,7 @@ package com.bonus.boot.manager.manager.filter;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@ -22,7 +21,7 @@ import com.bonus.boot.manager.manager.entity.LoginUser;
* Token过滤器
*/
@Component
public class TokenFilter extends OncePerRequestFilter {
public class TokenFilter extends OncePerRequestFilter implements Filter {
public static final String TOKEN_KEY = "token";
@ -45,14 +44,18 @@ public class TokenFilter extends OncePerRequestFilter {
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
// 在这里设置 CSP 头或其他过滤逻辑
response.setHeader(
"Content-Security-Policy",
"default-src 'self'; script-src 'self' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline';"
);
filterChain.doFilter(request, response);
}
/**
* 校验时间<br>
* 过期时间与当前时间对比临近过期10分钟内的话自动刷新缓存
*
*
* @param loginUser
* @return
*/
@ -70,7 +73,7 @@ public class TokenFilter extends OncePerRequestFilter {
/**
* 根据参数或者header获取token
*
*
* @param request
* @return
*/
@ -82,5 +85,4 @@ public class TokenFilter extends OncePerRequestFilter {
return token;
}
}

View File

@ -1,5 +1,5 @@
#\u8BBF\u95EE\u7AEF\u53E3
#\u6B63\u5F0F\u7AEF\u53E3
#\u6B63\u5F0F\u7AEF\u53E3
#server.port=18088
#\u672C\u5730\u7AEF\u53E3
server.port=18088
@ -73,4 +73,31 @@ files.path=/data/yn
#\u672C\u5730
#files.url=http://192.168.0.110:18088/YSpeaManager/statics
#files.path=d:\\data\\yn
#files.upload=d:\\files
#files.upload=d:\\files
# \u8DE8\u57DF\u914D\u7F6E
# \u5141\u8BB8\u7684\u6E90\uFF08\u591A\u4E2A\u7528\u9017\u53F7\u5206\u9694\uFF09
cors.allowed-origins=http://localhost:1616,http://127.0.0.1:1616,http://192.168.0.39:1616,http://192.168.0.14:1616,http://112.29.103.165:1616
# \u5141\u8BB8\u7684HTTP\u65B9\u6CD5
cors.allowed-methods=GET,POST,PUT,DELETE,OPTIONS
# \u5141\u8BB8\u7684\u8BF7\u6C42\u5934
cors.allowed-headers=Content-Type,X-Requested-With,Token,Authorization,X-Custom-Header
# \u662F\u5426\u5141\u8BB8\u643A\u5E26\u8BA4\u8BC1\u4FE1\u606F
cors.allow-credentials=true
# \u9884\u68C0\u8BF7\u6C42\u7F13\u5B58\u65F6\u95F4\uFF08\u79D2\uFF09
cors.max-age=3600
# \u5B89\u5168\u5934\u914D\u7F6E
# \u662F\u5426\u542F\u7528\u4E25\u683C\u7684\u5B89\u5168\u5934
security.headers.strict=true
# \u662F\u5426\u542F\u7528HSTS\uFF08HTTP\u4E25\u683C\u4F20\u8F93\u5B89\u5168\uFF09
security.hsts.enabled=true
# \u662F\u5426\u6E05\u9664\u670D\u52A1\u5668\u4FE1\u606F\u5934
security.headers.clear-server-info=true
management.endpoint.caches.enabled=false

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long