Java SSRF漏洞总结

Java SSRF关键字:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
HttpClient.execute
HttpClient.executeMethod
HttpURLConnection.connect
HttpURLConnection.getInputStream
URL.openStream
HttpServletRequest
getParameter
URI
URL
HttpClient
HttpServletRequest
HttpURLConnection
URLConnection
okhttp
BasicHttpEntityEnclosingRequest
DafauleBHttpClientConnection
BasicHttpRequest
...

Java下ssrf简单的示例:

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
public class Ssrf {
public static void main(String[] args) {
Ssrf ssrf = new Ssrf();
// ssrf.requestByURLConnection("http://www.baidu.com");
ssrf.requestByURLConnection("file:///E:/111.txt");
}

/**
* URLConnection支持的协议:file ftp mailto http https jar netdoc gopher
* gopher仅在java8以前支持,并且Java7高版本对gopher有限制
*/
private void requestByURLConnection(String url) {
// url = "file:///E:/111.txt";
// url = "http://www.baidu.com"
try {
if (this.urlFilterByWhiteList(url).equals("")){
return;
}

String htmlContent;
URL u = new URL(url); //实例化url的对象
URLConnection urlConnection = u.openConnection();//打开一个URL连接,并运行客户端访问资源。
// HttpURLConnection urlConnection1 = (HttpURLConnection) urlConnection; //转成HttpURLConnection
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "UTF-8"));//获取url中的资源
StringBuffer html = new StringBuffer();
while ((htmlContent = bufferedReader.readLine()) != null) {
html.append(htmlContent);
}
bufferedReader.close();
System.out.println(html);
} catch (Exception e) {
e.printStackTrace();
}
}

/**
* 过滤url,增加白名单校验
*/
private String urlFilterByWhiteList(String url) {
String[] whiteProtocolList = {"http://", "https://"};
String[] whiteUrlList = {"http://enable.com/","http://enable1.com/"};
boolean protocolFlag = false;
boolean urlFlag = false;

for (String list : whiteProtocolList) {
if (url.toLowerCase().contains(list) && url.toLowerCase().indexOf(list) == 0) {
protocolFlag = true;
break;
}
}
if(!protocolFlag){
return "";
}

for (String list : whiteUrlList) {
if (url.toLowerCase().contains(list) && url.toLowerCase().indexOf(list) == 0) {
urlFlag = true;
break;
}
}
if(!urlFlag){
return "";
}

return url;
}

/**
* 过滤url,增加黑名单校验
* 黑名单校验存在绕过风险
*/
private String urlFilterByBlackList(String url) {
String[] blackProtocolList = {"file", "ftp", "mailto", "jar", "netdoc", "gopher"};
String[] blackUrlList = {"192.168", "172.", "169.254"};
boolean protocolFlag = false;
boolean urlFlag = false;

for (String list : blackProtocolList) {
if (url.toLowerCase().contains(list) && url.toLowerCase().indexOf(list) == 0) {
protocolFlag = true;
break;
}
}
if(protocolFlag){
return "";
}

for (String list : blackUrlList) {
if (url.toLowerCase().contains(list) && url.toLowerCase().indexOf(list) == 0) {
urlFlag = true;
break;
}
}
if(urlFlag){
return "";
}

return url;
}

}

ssrf修复(来自《Java代码审计》):

1、统一错误信息,避免用户根据错误信息来判断远端服务器的端口状态。
2、限制请求的端口为 http 的常用端口,比如80、443、8080、8090等。
3、禁用不需要的协议,仅仅允许 http 和 https 请求。
4、根据业务需求,判定所需的域名是否是常用的几个,若是,则将这几个特定的域名加入白名单,拒绝白名单域名之外的请求。
5、根据请求来源,判定请求地址是否是固定请求来源,若是,则将这几个特定的域名/ IP添加到白名单,拒绝白名单域名/IP之外的请求。
6、若业务需求和请求来源并不固定,则可以自己编写一个 ssrfCheck 函数,检测特定的域名、判断是否是内网 IP 、判断是否为 http / https 协议等。

参考链接:

https://www.bookstack.cn/read/anbai-inc-javaweb-sec/javase-URLConnection-README.md