在https://blog.csdn.net/jimmyleeee/article/details/124733955说明了SSRF是怎么一会事,以及需要验证哪几个部分?
为了验证每一个部分,首先需要做的就是根据一个URL取出每一个部分的值,然后再根据取出来的值来进行判断。可能有的人会立刻想到将URL的字符串值转换成java.net.URL类,然后通过URL类的实例在获取每一个部分的内容,下面是根据URL缩写的代码示例以及测试代码:
package com.test.utils;
import java.net.MalformedURLException;
import java.net.URL;
public class URLUtil {
public static String getProtocol(String strUrl) {
try {
URL url =new URL(strUrl);
return url.getProtocol();
} catch (MalformedURLException e) {
e.printStackTrace();
}
return "";
}
public static String getHost(String strUrl) {
try {
URL url =new URL(strUrl);
return url.getHost();
} catch (MalformedURLException e) {
e.printStackTrace();
}
return "";
}
public static int getPort(String strUrl) {
try {
URL url =new URL(strUrl);
if (url.getPort() == -1) {
return url.getDefaultPort();
} else {
return url.getPort();
}
} catch (MalformedURLException e) {
e.printStackTrace();
}
return -1;
}
public static String getPath(String strUrl) {
try {
URL url =new URL(strUrl);
return url.getPath();
} catch (MalformedURLException e) {
e.printStackTrace();
}
return "";
}
public static void testURL() {
String url1="http://www.example.com/test/test1?query=test";
System.out.println("url1:protocol="+getProtocol(url1)+" host="+getHost(url1)
+ " port="+getPort(url1) + " Path=" +getPath(url1));
String url2="https://www.example.com/test/test1?query=test";
System.out.println("url2:protocol="+getProtocol(url2)+" host="+getHost(url2)
+ " port="+getPort(url2) + " Path=" +getPath(url2));
String url7="https://www.example.com:8443/test/test1?query=test";
System.out.println("url7:protocol="+getProtocol(url7)+" host="+getHost(url7)
+ " port="+getPort(url7) + " Path=" +getPath(url7));
String url3="http://www.example.com:80/test/test1?query=test";
System.out.println("url3:protocol="+getProtocol(url3)+" host="+getHost(url3)
+ " port="+getPort(url3) + " Path=" +getPath(url3));
String url4="http://127.0.0.1/test/test1?query=test";
System.out.println("url4:protocol="+getProtocol(url4)+" host="+getHost(url4)
+ " port="+getPort(url4) + " Path=" +getPath(url4));
String url5="http://127.0.0.1:80/test/test1?query=test";
System.out.println("url5:protocol="+getProtocol(url5)+" host="+getHost(url5)
+ " port="+getPort(url5) + " Path=" +getPath(url5));
String url6="https://127.0.0.1:8443/test/test1?query=test";
System.out.println("url6:protocol="+getProtocol(url6)+" host="+getHost(url6)
+ " port="+getPort(url6) + " Path=" +getPath(url6));
String url9="https://127.0.0.1:8443/test/test1?query=test";
System.out.println("url9:protocol="+getProtocol(url9)+" host="+getHost(url9)
+ " port="+getPort(url9) + " Path=" +getPath(url9));
String url8="ftps://127.0.0.1/test";
System.out.println("url8:protocol="+getProtocol(url8)+" host="+getHost(url8)
+ " port="+getPort(url8) + " Path=" +getPath(url8));
}
}
测试结果如下:
url1:protocol=http host=www.example.com port=80 Path=/test/test1
url2:protocol=https host=www.example.com port=443 Path=/test/test1
url7:protocol=https host=www.example.com port=8443 Path=/test/test1
url3:protocol=http host=www.example.com port=80 Path=/test/test1
url4:protocol=http host=127.0.0.1 port=80 Path=/test/test1
url5:protocol=http host=127.0.0.1 port=80 Path=/test/test1
url6:protocol=https host=127.0.0.1 port=8443 Path=/test/test1
url9:protocol=https host=127.0.0.1 port=8443 Path=/test/test1
java.net.MalformedURLException: unknown protocol: ftps
at java.net.URL.<init>(URL.java:617)
at java.net.URL.<init>(URL.java:507)
at java.net.URL.<init>(URL.java:456)
at com.test.utils.URLUtil.getProtocol(URLUtil.java:9)
at com.test.utils.URLUtil.testURL(URLUtil.java:89)
at com.test.LargestApplication.main(LargestApplication.java:79)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
java.net.MalformedURLException: unknown protocol: ftps
at java.net.URL.<init>(URL.java:617)
at java.net.URL.<init>(URL.java:507)
at java.net.URL.<init>(URL.java:456)
at com.test.utils.URLUtil.getHost(URLUtil.java:20)
at com.test.utils.URLUtil.testURL(URLUtil.java:89)
at com.test.LargestApplication.main(LargestApplication.java:79)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
java.net.MalformedURLException: unknown protocol: ftps
at java.net.URL.<init>(URL.java:617)
at java.net.URL.<init>(URL.java:507)
at java.net.URL.<init>(URL.java:456)
at com.test.utils.URLUtil.getPort(URLUtil.java:31)
at com.test.utils.URLUtil.testURL(URLUtil.java:90)
at com.test.LargestApplication.main(LargestApplication.java:79)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
java.net.MalformedURLException: unknown protocol: ftps
at java.net.URL.<init>(URL.java:617)
at java.net.URL.<init>(URL.java:507)
at java.net.URL.<init>(URL.java:456)
at com.test.utils.URLUtil.getPath(URLUtil.java:46)
at com.test.utils.URLUtil.testURL(URLUtil.java:90)
at com.test.LargestApplication.main(LargestApplication.java:79)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
发现试用ftps协议时,出现了异常。根据代码调试发现URL只支持HTTP、HTTPS、file三种协议,所以其他协议都会报java.net.MalformedURLException的异常。
于是,又转换了一下想法,使用java.net.URI类又实现了一个,代码示例如下:
package com.test.utils;
import java.net.URI;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;
public class URIUtil {
private String strUrl = null;
private URI uri = null;
private Map<String, String> defaultPorts = null;
public URIUtil(String url) {
strUrl = url;
uri = URI.create(strUrl);
defaultPorts =Protocols.getMap();
}
public String getProtocol() {
return uri.getScheme();
}
public String getHost() {
return uri.getHost();
}
public int getPort() {
return uri.getPort() == -1? getDefaultPort() : uri.getPort();
}
public String getPath() {
return uri.getPath();
}
private int getDefaultPort() {
String protocol = getProtocol();
if (protocol != null) {
String defaultPort = defaultPorts.get(protocol.toUpperCase());
if (defaultPort != null ){
return Integer.valueOf(defaultPort);
}
}
return -1;
}
public enum Protocols{
HTTP("HTTP", "80"),
HTTPS("HTTPS", "443");
private String name;
private String port;
private Protocols(String name, String port) {
this.name = name;
this.port = port;
}
public String getName() {
return name;
}
public String getPort() {
return port;
}
public static Map<String, String> getMap() {
Map<String, String> map = Arrays.asList(Protocols.values()).stream().collect(Collectors.toMap
(obj->obj.getName(),Protocols::getPort));
return map;
}
}
public static void testURI() {
String uri1="http://www.example.com/test/test1?query=test";
URIUtil uriUtil1 = new URIUtil(uri1);
System.out.println("uri1:protocol="+uriUtil1.getProtocol()+" host="+uriUtil1.getHost()
+ " port="+uriUtil1.getPort() + " Path=" +uriUtil1.getPath());
String uri2="https://www.example.com/test/test1?query=test";
URIUtil uriUtil2 = new URIUtil(uri2);
System.out.println("uri2:protocol="+uriUtil2.getProtocol()+" host="+uriUtil2.getHost()
+ " port="+uriUtil2.getPort() + " Path=" +uriUtil2.getPath());
String uri7="https://www.example.com:8443/test/test1?query=test";
URIUtil uriUtil7 = new URIUtil(uri7);
System.out.println("uri7:protocol="+uriUtil7.getProtocol()+" host="+uriUtil7.getHost()
+ " port="+uriUtil7.getPort() + " Path=" +uriUtil7.getPath());
String uri3="http://www.example.com:80/test/test1?query=test";
URIUtil uriUtil3 = new URIUtil(uri3);
System.out.println("uri3:protocol="+uriUtil3.getProtocol()+" host="+uriUtil3.getHost()
+ " port="+uriUtil3.getPort() + " Path=" +uriUtil3.getPath());
String uri4="http://127.0.0.1/test/test1?query=test";
URIUtil uriUtil4 = new URIUtil(uri4);
System.out.println("uri4:protocol="+uriUtil4.getProtocol()+" host="+uriUtil4.getHost()
+ " port="+uriUtil4.getPort() + " Path=" +uriUtil4.getPath());
String uri5="http://127.0.0.1:80/test/test1?query=test";
URIUtil uriUtil5 = new URIUtil(uri5);
System.out.println("uri5:protocol="+uriUtil5.getProtocol()+" host="+uriUtil5.getHost()
+ " port="+uriUtil5.getPort() + " Path=" +uriUtil5.getPath());
String uri6="https://127.0.0.1:8443/test/test1?query=test";
URIUtil uriUtil6 = new URIUtil(uri6);
System.out.println("uri6:protocol="+uriUtil6.getProtocol()+" host="+uriUtil6.getHost()
+ " port="+uriUtil6.getPort() + " Path=" +uriUtil6.getPath());
String uri9="https://127.0.0.1:8443/test/test1?query=test";
URIUtil uriUtil9 = new URIUtil(uri9);
System.out.println("uri9:protocol="+uriUtil9.getProtocol()+" host="+uriUtil9.getHost()
+ " port="+uriUtil9.getPort() + " Path=" +uriUtil9.getPath());
String uri8="ftps://127.0.0.1/test";
URIUtil uriUtil8 = new URIUtil(uri8);
System.out.println("uri8:protocol="+uriUtil8.getProtocol()+" host="+uriUtil8.getHost()
+ " port="+uriUtil8.getPort() + " Path=" +uriUtil8.getPath());
String uri10="ftps://127.0.0.1:29/test";
URIUtil uriUtil10 = new URIUtil(uri10);
System.out.println("uri10:protocol="+uriUtil10.getProtocol()+" host="+uriUtil10.getHost()
+ " port="+uriUtil10.getPort() + " Path=" +uriUtil10.getPath());
String uri11="gropher://127.0.0.1:29/test";
URIUtil uriUtil11 = new URIUtil(uri11);
System.out.println("uri11:protocol="+uriUtil11.getProtocol()+" host="+uriUtil11.getHost()
+ " port="+uriUtil11.getPort() + " Path=" +uriUtil11.getPath());
String uri12="test://127.0.0.1:29/test";
URIUtil uriUtil12 = new URIUtil(uri12);
System.out.println("uri12:protocol="+uriUtil12.getProtocol()+" host="+uriUtil12.getHost()
+ " port="+uriUtil12.getPort() + " Path=" +uriUtil12.getPath());
String uri13="/test/relativepath";
URIUtil uriUtil13 = new URIUtil(uri13);
System.out.println("uri13:protocol="+uriUtil13.getProtocol()+" host="+uriUtil13.getHost()
+ " port="+uriUtil13.getPort() + " Path=" +uriUtil13.getPath());
String uri14="https://api.example.com/test/test1?query=test";
URIUtil uriUtil14 = new URIUtil(uri14);
System.out.println("uri14:protocol="+uriUtil14.getProtocol()+" host="+uriUtil14.getHost()
+ " port="+uriUtil14.getPort() + " Path=" +uriUtil14.getPath());
}
}
测试结果如下:
uri1:protocol=http host=www.example.com port=80 Path=/test/test1
uri2:protocol=https host=www.example.com port=443 Path=/test/test1
uri7:protocol=https host=www.example.com port=8443 Path=/test/test1
uri3:protocol=http host=www.example.com port=80 Path=/test/test1
uri4:protocol=http host=127.0.0.1 port=80 Path=/test/test1
uri5:protocol=http host=127.0.0.1 port=80 Path=/test/test1
uri6:protocol=https host=127.0.0.1 port=8443 Path=/test/test1
uri9:protocol=https host=127.0.0.1 port=8443 Path=/test/test1
uri8:protocol=ftps host=127.0.0.1 port=-1 Path=/test
uri10:protocol=ftps host=127.0.0.1 port=29 Path=/test
uri11:protocol=gropher host=127.0.0.1 port=29 Path=/test
uri12:protocol=test host=127.0.0.1 port=29 Path=/test
uri13:protocol=null host=null port=-1 Path=/test/relativepath
uri14:protocol=https host=api.example.com port=443 Path=/test/test1
效果和预期的一样。
不过,在代码里对于没有提供端口的情况进行了一些特殊处理,因为使用的URL中如果没有端口的话,默认的都会返回-1,代码中通过定义了某些协议的默认端口,如果没有端口的话,就使用默认的端口代替。