SV.SSRF.URI
URI 基于失效的用户输入。
SV.SSRF.URI 检查器会标记以下情况:Java Web 服务器应用程序收到来自上游组件的 URL 或类似请求并检索此 URL 的内容,但未充分确保将请求发送到预期目标。
从 2023.2 版本开始,此检查器将支持 Jakarta EE。
漏洞与风险
服务器端请求伪造 (SSRF) 这种攻击载体会滥用应用程序,来与外部或内部网络或者计算机本身进行交互。促成这种载体的原因之一是对不同类型的 URL 处理不当,例如:
- 外部服务器上的图像文件,例如,用户输入其头像图片的 URL,供应用程序下载和使用。
- 自定义 Webhook,用户在其中指定 Webhook 处理程序或回调 URL。
-
内部请求,请求与另一个服务进行交互以提供特定函数。经常会发送用户数据以进行处理,如果处理不当,可能会导致注入攻击。
请注意,SSRF 并非仅限于 HTTP 协议。第一个请求通常为 HTTP,但是如果应用程序本身执行第二个请求,它可能会使用其他协议(例如 FTP、SMB、SMTP)或方案(例如 file://、phar://、gopher://、data://、dict:// 等)。
如果应用程序容易遭受 XML 外部实体 (XXE) 注入,那么它可能会被利用以执行 SSRF 攻击
缓解与预防
确保所提供的 IP 地址属于已识别的可信应用程序的 IP 地址。
漏洞代码示例
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
public class SV_SSRF_URI_POSITIVE_JAKARTA {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException,URISyntaxException, InterruptedException {
HttpClient client = HttpClient.newHttpClient();
String url = req.getParameter("uri");
URI uri = new URI(url);
// BAD: a request parameter is incorporated without validation into a Http request
HttpRequest r = HttpRequest.newBuilder(uri).build();
client.send(r, null);
}
}
在此示例中,通过使用 req.getParameter("uri") 从 HttpServletRequest 中提取的 String URL 参数正用于 HttpRequest 连接,但未经过验证。Klocwork 在第 13 行报告了缺陷,指出“失效的用户输入被用作 URI 对象的一部分”。
修正代码示例
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
public class SV_SSRF_URI_POSITIVE_JAKARTA {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, URISyntaxException, InterruptedException {
HttpClient client = HttpClient.newHttpClient();
// GOOD: the request parameter is validated against a known fixed string or valid source of IP address
String url = req.getParameter("uri");
if (VALID_URI.equals(url)) {
URI uri = new URI(url);
HttpRequest r = HttpRequest.newBuilder(uri).build();
client.send(r, null);
}
}
在此修正示例中,Klocwork 不再报告缺陷,因为使用 req.getParameter("uri") 从 HttpServletRequest 中提取的 URL 参数在用于 HttpRequest 连接之前,已针对可信的 URL 进行了验证。
扩展
可调整此检查器,以检查用户是否经过授权以访问项目中使用的受保护的 API。可以通过在 .jkb 文件中使用 @CheckerParam 选项来进行此操作。有关详情,请参阅调整 Java 分析。