介绍
SSRF(Server-Side Request Forgery:服务器端请求伪造)是一种有攻击者构造形成由服务器端发起请求的一个安全漏洞。攻击者可以利用该漏洞服务器端应用程序向攻击者选择的任意域发出HTTP请求。
简单来说两个地址A,B,两个网址都在同一个服务器下,用户只有访问A的权限,通过服务器伪造命令,利用A的权限登录B。
危害
-
对服务器所在内网或本地进行端口扫描,获取到服务的banner信息
-
攻击运行在内网或本地的应用程序
-
对内网web应用进行指纹识别,通过访问默认文件实现
-
攻击内外网的web应用,使用get参数实现struts2,sql注入等。
-
下载内网资源,利用file协议读取本地文件。
-
利用Redis未授权访问,HTTP CRLF注入达到getshell
修复
通过配置白名单修复问题
//校验过程
public boolean ssrfFilter(String externalUrl) throws MalformedURLException {
URL url = new URL(externalUrl);
String domain = url.getHost();
if (!domainFilter(domain)){
return false;
}
String secondaryDomain = getSecondaryDomain(domain);
//从配置或者redis中获取白名单
List<String> whiteList = new ArrayList<>();
for (Iterator<String> it = whiteList.iterator(); it.hasNext();) {
String value = it.next();
if(secondaryDomain.equals(value)){
return true;
}
}
return false;
}
private static String getSecondaryDomain(String domain) {
String[] domains = domain.split("\\.");
return domains[domains.length - 2] + "." + domains[domains.length - 1];
}
//域名有效字符校验,防止使用反斜线等特殊字符进行绕过
private static boolean domainFilter(String domain) {
String regex = "[^a-zA-Z0-9\\.-]";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(domain);
return !matcher.find();
}
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
public class SSRFFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// 检查所有请求参数
Enumeration<String> parameterNames = httpRequest.getParameterNames();
while (parameterNames.hasMoreElements()) {
String parameterName = parameterNames.nextElement();
String[] parameterValues = httpRequest.getParameterValues(parameterName);
for (String parameterValue : parameterValues) {
if (isPotentialUrl(parameterValue)) {
if (!ssrfFilter(parameterValue)) {
// 拒绝访问并返回错误响应
httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "URL is not allowed.");
return;
}
}
}
}
// 如果URL在白名单中或不是URL参数,则继续处理请求
chain.doFilter(request, response);
}
//URL检测
private boolean isPotentialUrl(String input) {
return input.matches("^(https?|ftp):\/\/([a-zA-Z0-9-\.]+\.[a-zA-Z]{2,6})(:[0-9]+)?(\/[a-zA-Z0-9_\-\/]*)*(\?[a-zA-Z0-9_&=\-%]*)?(#[a-zA-Z0-9_\-]*)?$");
}
@Override
public void destroy() {
}
}
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<SSRFFilter> ssrfFilter() {
FilterRegistrationBean<SSRFFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new SSRFFilter());
registrationBean.addUrlPatterns("/*");
return registrationBean;
}
}
标签:domain,return,修复,SSRF,URL,漏洞,import,public,String
From: https://blog.csdn.net/m0_52796363/article/details/143803190