Java基础:URLConnection

文章发布时间:

最后更新时间:

文章总字数:
1k

预计阅读时间:
4 分钟

Java基础:URLConnection

本文主要介绍如何利用java建立URL通信连接,有点像python的request。

URL请求发起流程

在java中,Java抽象出来了一个URLConnection类,它用来表示应用程序以及与URL建立通信连接的所有类的超类,通过URL类中的openConnection方法获取到URLConnection的类对象。

sun.net.www下面可以查看所有支持的协议:

image-20230903095229378

我们可以写一个url请求的demo来感受一下java如何发起url请求:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

public class URLConnDemo {
public static String inputStreamToString(InputStream in, String charset) throws IOException {
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
int a = 0;
byte[] b = new byte[1024];

while ((a = in.read(b)) != -1) {
out.write(b, 0, a);
}

return out.toString();
} finally {
if (in != null)
in.close();
}
}
public static void main(String[] args) throws Exception{
URL url = new URL("https://pazuris.cn");
//先使用想要连接的url创建URL对象
URLConnection connection = url.openConnection();
//然后使用刚刚的URL对象创建URLConnection对象来进行连接
connection.setRequestProperty("user-agent","javasec");
//设置请求包,每使用一次setRequestProperty就设置一对键值,可以使用map加循环语句设置
connection.setConnectTimeout(1000);
connection.setReadTimeout(1000);
//设置响应的等待时间
connection.connect();
//这里正式进行连接
String headlines = connection.getHeaderFields().toString();
System.out.println(headlines);
//获取响应头,格式为map,可以toString输出
String response = inputStreamToString(connection.getInputStream(),"UTF-8");
System.out.println(response);
//获取响应数据,格式为inputStream,可以转换输出
}

}

总的来说,java的url请求比python麻烦不少,所以爬虫都是用python写的(python还有靓汤库)

Java下的SSRF

SSRF(Server-side Request Forge, 服务端请求伪造)。 由攻击者构造的攻击链接传给服务端执行造成的漏洞,伪造成服务器端127.0.0.1的请求,一般用来在外网探测或攻击内网服务。

SSRF漏洞形成的原因大部分是因为服务端提供了可以从其他服务器获取资源的功能,然而并没有对用户的输入以及发起请求的url进行过滤&限制(限制协议和url内容),从而导致了ssrf的漏洞。

通常ssrf容易出现的功能点如下面几种场景

  • 抓取用户输入图片的地址并且本地化存储
  • 从远程服务器请求资源
  • 对外发起网络请求

任意文件读取

比如假如上面代码中的url可控,那么将url参数传入为file:///etc/passwd就可以读到文件内容

1
2
3
URL url = new URL("file:///etc/passwd");
URLConnection connection = url.openConnection();
connection.connect();

但是如果上述代码中将url.openConnection()返回的对象强转为HttpURLConnection,则会抛出异常

也就是说,ssrf漏洞对使用不同类发起的url请求也是有所区别的,如果是URLConnection|URL发起的请求,那么对于上文中所提到的所有protocol都支持,但是如果经过二次包装或者其他的一些类发出的请求,比如

1
2
3
4
5
HttpURLConnection
HttpClient
Request
okhttp
……

那么只支持发起http|https协议,否则会抛出异常。这就给了我们防御ssrf的思路。

内网探测

传入127.0.0.1:80,如果是web端口,则会把网页源码输出,如果是非web端口的服务,则会马上爆出异常并抛出,如果该端口没有在使用,则会过很久,然后抛出异常,通过bp爆破即可实现对内网所有服务端口的检测。

由于各种对协议的判断和限制,Java的SSRF漏洞利用方式整体比较有限,大概就是上面提到的这两种了,而对于防御ssrf攻击,不单单要对协议进行控制,也需要对其中访问的地址进行限制过滤。但是对于过滤我们也有很多绕过方式(比如在本机host文件上绑定某域名为127.0.0.1,通过输入该域名来实现ssrf,更多方式可以参考ctfshow的ssrf靶场)。