SSRF(Server-Side Request Forgery)是一种通过构造请求,由目标系统服务端发起请求的安全漏洞。SSRF攻击可被用于非法访问内网地址,甚至直接访问被攻击主机的文件内容,通常都有较大危害。
可能存在SSRF漏洞的系统通常具备这样的特点:支持用户输入一个URL地址,服务端接收URL并根据它请求数据,最后将获得的数据进一步处理或是直接返回给用户。举例来说,如果服务端存在接收类似这种请求参数的功能:http://127.0.0.1/getFileData?url=http%3A%2F%2F192.168.1.101%2Ffiles%2F1.jpg
,那么就有可能存在SSRF漏洞!攻击者可能会精心构造URL参数,来用HTTP、FTP等协议非法访问内网资源,或是使用File协议访问主机上的文件。
补充知识:URL全名为统一资源定位符,除了HTTP外还支持许多种协议,各类编程语言对URL协议的支持可能各不相同,例如Java的URL
类支持http
、https
、ftp
、file
、gopher
协议等。
下面是使用SpringBoot编写的例子程序,其中/getFileData
接口接收urlBase64
参数,它是一个URL地址(为了方便作为GET参数而进行了Base64编码),服务端程序接收到请求后会读取URL地址的内容并返回给客户端。然而实际上该接口存在严重漏洞,攻击者构造一个读取file
协议的请求就可以读取主机上的文件。
package com.gacfox.demo.demoboot;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
@Controller
public class DemoController {
@GetMapping("/getFileData")
public void getFileData(String urlBase64, HttpServletResponse httpServletResponse) {
try {
Base64 base64 = new Base64();
String urlStr = new String(base64.decode(urlBase64), StandardCharsets.UTF_8);
URL url = new URL(urlStr);
URLConnection urlConnection = url.openConnection();
urlConnection.connect();
try (InputStream inputStream = urlConnection.getInputStream();
ServletOutputStream servletOutputStream = httpServletResponse.getOutputStream()) {
IOUtils.copy(inputStream, servletOutputStream);
} catch (IOException e) {
e.printStackTrace();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
构造攻击请求的思路如下:
D://flag.txt
,其对应file
协议写法为:file:///d:/flag.txt
file:///d:/flag.txt
按服务端的处理格式进行Base64编码:ZmlsZTovLy9kOi9mbGFnLnR4dA==
/getFileData
接口:http://localhost:8080/getFileData?urlBase64=ZmlsZTovLy9kOi9mbGFnLnR4dA==
此时我们就可以读取到主机上的文件了。
SSRF漏洞主要是由于后端开发人员缺乏安全意识造成的,我们编写类似功能时,需要注意以下几点: