前言

Github:https://github.com/HealerJean

博客:http://blog.healerjean.com

一、SSRF是什么

SSRF(Server-Side Request Forgery)是一种网络安全攻击手段,也被称为服务器端请求伪造。这种攻击允许攻击者通过一个易受攻击的 Web 应用程序,发送恶意请求到其他网站。

具体来说,当服务端提供了从其他服务器获取数据的功能(如从指定 URL 地址获取网页文本内容、加载指定地址的图片、下载等),但没有对目标地址做过滤与限制时,就可能出现 SSRF 漏洞。攻击者可以构造请求,使服务端发起请求,从而访问到与外网隔离的内部系统资源。

SSRF 形成的主要原因是由于服务端提供了从其他服务器应用获取数据的功能且没有对目标地址做过滤与限制。比如从指定URL地址获取网页文本内容、加载指定地址的图片等

SSRF 攻击的目标一般是从外网无法访问的内部系统,其攻击手法包括但不限于访问其他站点、内网获取信息,利用伪协议读取或写入文件等。为了防止 SSRF 攻击,可以采取一些防御措施,如严格的输入验证、限制服务器请求、使用安全列表以及禁用不必要的服务等。

请注意,防御 SSRF 攻击需要综合考虑多种因素,并根据具体情况采取相应的措施。同时,保持对安全漏洞和攻击手法的了解,及时更新和升级系统和应用程序,也是减少SSRF攻击风险的重要措施。

二、防御

输入验证和过滤:对从用户输入中获取的URL进行严格的验证和过滤,确保只接受合法的URL。使用白名单过滤机制,限制URL只能访问特定的域名或IP地址,从而防止攻击者构造恶意请求。

限制协议和端口:限制服务器端应用程序只能发起特定协议(如HTTP和HTTPS)和特定端口范围内的请求。同样,使用白名单机制,只允许特定的协议和端口,以减少潜在的攻击面。

内网访问限制:确保服务器端应用程序只能发起外部网络的请求,禁止访问内部网络。利用网络隔离技术,将服务器部署在DMZ(Demilitarized Zone)区域,只允许与外部网络通信,以防止SSRF攻击利用内部网络资源。

更新相关组件和框架:及时更新服务器端应用程序使用的相关组件和框架,以修复已知的SSRF漏洞。保持系统和应用程序的最新版本,可以减少被利用的风险。

强制访问控制:使用身份验证和授权机制,限制用户访问特定的功能和资源。这有助于防止未经授权的请求被发送,从而减少SSRF攻击的可能性。

/**
 * @param url url
 * @return boolean
 */
public static boolean sslfUrl(String url) {
    // 1、验证url是否合法
    URL urlObj = null;
    try {
        urlObj = new URL(url);
    } catch (Exception e) {
        log.error("[SSLFUtils#passSslfUrl] url不合法 url:{}", url);
        return false;
    }

    // 2、协议必须是 http、https
    Set<String> allowProtocols = new HashSet<>();
    allowProtocols.add("http");
    allowProtocols.add("https");
    if (!allowProtocols.contains(urlObj.getProtocol())) {
        log.error("[SSLFUtils#passSslfUrl] url协议非http协议 url:{}", url);
        return false;
    }

    // 3、域名必须合法
    Set<String> allowDomains = new HashSet<>();
    allowDomains.add("blog.healerjean.com");
    if (!allowDomains.contains(urlObj.getHost())) {
        log.error("[SSLFUtils#passSslfUrl] 域名不合法 url:{}", url);
        return false;
    }

    // 4、端口必须是 80、443
    Set<String> allowPorts = new HashSet<>();
    allowPorts.add("80");
    allowPorts.add("443");
    String port = urlObj.getPort() == -1 ? "80" : String.valueOf(urlObj.getPort());
    if (!allowPorts.contains(port)) {
        log.error("[SSLFUtils#passSslfUrl] url协议非http协议 url:{}", url);
        return false;
    }
    return true;
}

ContactAuthor