网站推广 方法,秦皇岛乾兴建设工程,wordpress 电子杂志,做网站培训未经许可#xff0c;不得转载。 文章目录 SSRF漏洞成因Java中发送HTTP请求的函数1、HttpURLConnection2、HttpClient#xff08;Java 11#xff09;3、第三方库Request库漏洞示例OkHttpClient漏洞示例HttpClients漏洞示例 漏洞代码示例防范标准代码 SSRF
SSRF#xff08;S… 未经许可不得转载。 文章目录 SSRF漏洞成因Java中发送HTTP请求的函数1、HttpURLConnection2、HttpClientJava 113、第三方库Request库漏洞示例OkHttpClient漏洞示例HttpClients漏洞示例 漏洞代码示例防范标准代码 SSRF
SSRFServer-Side Request Forgery服务器端请求伪造 是一种安全漏洞攻击者可以利用该漏洞诱使服务器向内部或外部的任意系统发起请求。通过SSRF攻击者可以绕过防火墙或访问限制访问内部资源甚至攻击内网中的其他服务。
常见的攻击场景包括 1、访问内网中的敏感数据。 2、扫描内网端口和服务。 3、利用服务器作为跳板攻击其他系统。 4、访问云服务元数据如AWS的元数据服务。
漏洞成因
SSRF漏洞通常是由于应用程序在处理用户输入的URL时未对其进行严格的验证和过滤导致攻击者可以构造恶意URL使服务器发起非预期的请求。
Java中发送HTTP请求的函数
在Java中发送HTTP请求的常见方式有以下几种。
1、HttpURLConnection
这是Java标准库中的类用于发送HTTP请求示例代码如下
import java.net.HttpURLConnection; // 导入HttpURLConnection类
import java.net.URL; // 导入URL类
import java.io.BufferedReader; // 导入BufferedReader类
import java.io.InputStreamReader; // 导入InputStreamReader类public class HttpExample {public static void main(String[] args) {try {// 创建URL对象并指定要访问的地址URL url new URL(https://example.com);// 打开与目标URL的连接HttpURLConnection conn (HttpURLConnection) url.openConnection();// 设置请求方法为GETconn.setRequestMethod(GET);// 创建BufferedReader读取响应内容BufferedReader in new BufferedReader(new InputStreamReader(conn.getInputStream()));String inputLine;StringBuilder content new StringBuilder();// 逐行读取响应并拼接while ((inputLine in.readLine()) ! null) {content.append(inputLine);}// 关闭输入流in.close();// 断开连接conn.disconnect();// 打印网页内容System.out.println(content.toString());} catch (Exception e) {e.printStackTrace(); // 捕获异常并打印错误信息}}
}2、HttpClientJava 11
Java 11引入的新的HTTP客户端API功能更强大。
3、第三方库
如Apache HttpClient、OkHttp等。
Request库漏洞示例
String url request.getParameter(url); // 从用户输入中获取URL
return Request.Get(url).execute().returnContent().toString(); // 直接使用用户输入的URL发起请求代码直接从用户输入中获取URL未进行任何验证或过滤。
OkHttpClient漏洞示例
String url request.getParameter(url); // 从用户输入中获取URL
OkHttpClient client new OkHttpClient();
com.squareup.okhttp.Request ok_http new com.squareup.okhttp.Request.Builder().url(url).build();
client.newCall(ok_http).execute(); // 使用用户输入的URL发起请求代码直接使用用户输入的URL构造请求未对URL进行合法性检查。
HttpClients漏洞示例
String url request.getParameter(url); // 从用户输入中获取URL
CloseableHttpClient client HttpClients.createDefault();
HttpGet httpGet new HttpGet(url);
HttpResponse httpResponse client.execute(httpGet); // 使用用户输入的URL发起请求代码未对用户输入的URL进行任何验证或限制直接用于发起HTTP请求。
漏洞代码示例
import java.net.HttpURLConnection;
import java.net.URL;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import javax.servlet.http.HttpServletRequest;public class SSRFExample {public static void main(String[] args) {HttpServletRequest request getRequest();// 获取请求中的 URL 参数String userInput request.getParameter(url);if (userInput null || userInput.isEmpty()) {System.out.println(Please provide a URL as a parameter.);return;}try {// 创建URL对象URL url new URL(userInput);HttpURLConnection conn (HttpURLConnection) url.openConnection();conn.setRequestMethod(GET); //GET方法请求// 读取响应内容BufferedReader in new BufferedReader(new InputStreamReader(conn.getInputStream()));String inputLine;StringBuilder content new StringBuilder();while ((inputLine in.readLine()) ! null) {content.append(inputLine);}in.close();conn.disconnect();// 打印响应内容System.out.println(content.toString());} catch (Exception e) {e.printStackTrace(); // 捕获异常并打印错误信息}}
}在这个示例中用户输入的URL直接用于发起HTTP请求如果攻击者输入一个指向内网服务的URL如http://169.254.169.254/latest/meta-data/服务器会访问到敏感的内部资源并返回给客户端。
防范
1、严格验证用户输入的 URL确保其符合预期格式和范围。
2、合理处理 302 跳转对跳转地址进行校验而非直接禁止。
3、限制协议类型仅允许 http/https禁止跨协议访问。
4、采用白名单机制仅允许访问特定域名或 IP 地址
准确识别内网 IP并正确解析 Host 头信息。禁止访问内网 IP 地址及私有 IP 段如 127.0.0.1、192.168.x.x、10.x.x.x 等。拒绝访问敏感 URL如云服务元数据地址。
5、配置 Web 端口白名单防止端口扫描可能对业务有一定限制。
标准代码
private static final int CONNECT_TIMEOUT 5000; // 连接超时时间毫秒public static boolean checkSsrf(String url) {HttpURLConnection connection;String finalUrl url;try {do {// 仅允许 http/https 协议防止跨协议攻击if (!Pattern.matches(^https?://.$, finalUrl)) {return false;}// 判断是否为内网 IP避免 SSRF 访问内部服务if (isInnerIp(finalUrl)) {return false;}// 发起 HTTP 请求不跟随跳转connection (HttpURLConnection) new URL(finalUrl).openConnection();connection.setInstanceFollowRedirects(false); // 禁止自动跳转connection.setUseCaches(false); // 禁用缓存确保每次请求都重新解析 DNSconnection.setConnectTimeout(CONNECT_TIMEOUT); // 设置超时时间防止长时间阻塞connection.connect(); // 触发 DNS 解析尝试建立连接int statusCode connection.getResponseCode();// 检查 3xx 状态码重定向但排除 304缓存和 306保留未使用if (statusCode 300 statusCode 307 statusCode ! 304 statusCode ! 306) {String redirectedUrl connection.getHeaderField(Location);if (redirectedUrl null) {break; // 若无重定向地址则终止检查}finalUrl redirectedUrl; // 继续检查跳转后的 URL} else {break; // 结束循环URL 无需进一步检查}} while (connection.getResponseCode() ! HttpURLConnection.HTTP_OK); // 仅当返回 200 时才终止检查connection.disconnect();} catch (Exception e) {return true; // 捕获异常返回 true默认安全策略}return true;
}private static boolean isInnerIp(String url) throws URISyntaxException, UnknownHostException {URI uri new URI(url);String host uri.getHost(); // 提取 Host 部分// 解析 Host 对应的 IP 地址并标准化为 IPv4 格式InetAddress inetAddress InetAddress.getByName(host);String ip inetAddress.getHostAddress();// 定义内网 IP 段私有地址范围String[] privateSubnets {10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8};for (String subnet : privateSubnets) {SubnetUtils subnetUtils new SubnetUtils(subnet); // 使用 commons-net 进行子网匹配if (subnetUtils.getInfo().isInRange(ip)) {return true; // IP 属于内网地址范围返回 true}}return false;
}说明 1、return false → 发现安全问题时如协议不合法、检测到内网 IP返回 false表示 URL 不安全。 2、return true → 没有发现明确安全问题返回 true允许执行。