!253 修复:非法请求使过滤器失效,出现严重安全问题

* BaseUrlFilter 修改过滤全部路径,保证 BaseUrlFilter 优于UrlCheckFilter 执行
* 清除无用 html
* 非法请求过滤器: 修复请求 path 中包含 // 或者以 / 结尾导致其它过滤器失效,对请求进行重定向
* 非法请求过滤器: 替换 getRequestURI() 为 getServletPath()
* 非法请求过滤器: 截取 context-path
* 非法请求过滤器: 去除 context-path
* 非法请求过滤器: 排除首页path "/"
* 非法请求过滤器: 请求地址中包含"//"或者以"/"结尾时导致其他过滤器失效,比如 TrustHostFilter
This commit is contained in:
Moomel 2024-02-21 02:56:54 +00:00 committed by 陈精华
parent bef81a940e
commit 448a700687
2 changed files with 64 additions and 4 deletions

View File

@ -30,11 +30,13 @@ public class WebConfig implements WebMvcConfigurer {
registry.addResourceHandler("/**").addResourceLocations("classpath:/META-INF/resources/","classpath:/resources/","classpath:/static/","classpath:/public/","file:" + filePath);
}
@Bean
public FilterRegistrationBean<ChinesePathFilter> getChinesePathFilter() {
ChinesePathFilter filter = new ChinesePathFilter();
FilterRegistrationBean<ChinesePathFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(filter);
registrationBean.setOrder(10);
return registrationBean;
}
@ -67,14 +69,20 @@ public class WebConfig implements WebMvcConfigurer {
@Bean
public FilterRegistrationBean<BaseUrlFilter> getBaseUrlFilter() {
Set<String> filterUri = new HashSet<>();
filterUri.add("/index");
filterUri.add("/");
filterUri.add("/onlinePreview");
filterUri.add("/picturesPreview");
BaseUrlFilter filter = new BaseUrlFilter();
FilterRegistrationBean<BaseUrlFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(filter);
registrationBean.setUrlPatterns(filterUri);
registrationBean.setOrder(20);
return registrationBean;
}
@Bean
public FilterRegistrationBean<UrlCheckFilter> getUrlCheckFilter() {
UrlCheckFilter filter = new UrlCheckFilter();
FilterRegistrationBean<UrlCheckFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(filter);
registrationBean.setOrder(30);
return registrationBean;
}

View File

@ -0,0 +1,52 @@
package cn.keking.web.filter;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @date 2023/11/30
*/
public class UrlCheckFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String servletPath = httpServletRequest.getServletPath();
boolean redirect = false;
// servletPath 中不能包含 //
if (servletPath.contains("//")) {
servletPath = servletPath.replaceAll("//+", "/");
redirect = true;
}
// 不能以 / 结尾同时考虑 **首页** 的特殊性
if (servletPath.endsWith("/") && servletPath.length() > 1) {
servletPath = servletPath.substring(0, servletPath.length() - 1);
redirect = true;
}
if (redirect) {
String redirectUrl;
if (StringUtils.isBlank(BaseUrlFilter.getBaseUrl())) {
// 正常 BaseUrlFilter 有限此 Filter 执行不会执行到此
redirectUrl = httpServletRequest.getContextPath() + servletPath;
} else {
if (BaseUrlFilter.getBaseUrl().endsWith("/") && servletPath.startsWith("/")) {
// BaseUrlFilter.getBaseUrl() / 结尾servletPath / 开头需再去除一次 //
redirectUrl = BaseUrlFilter.getBaseUrl() + servletPath.substring(1);
} else {
redirectUrl = BaseUrlFilter.getBaseUrl() + servletPath;
}
}
((HttpServletResponse) response).sendRedirect(redirectUrl + "?" + httpServletRequest.getQueryString());
} else {
chain.doFilter(request, response);
}
}
}