diff --git a/.idea/libraries/Maven__javax_servlet_servlet_api_2_5.xml b/.idea/libraries/Maven__javax_servlet_servlet_api_2_5.xml
new file mode 100644
index 0000000..679e09a
--- /dev/null
+++ b/.idea/libraries/Maven__javax_servlet_servlet_api_2_5.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_apache_commons_commons_lang3_3_0.xml b/.idea/libraries/Maven__org_apache_commons_commons_lang3_3_0.xml
new file mode 100644
index 0000000..de0cf71
--- /dev/null
+++ b/.idea/libraries/Maven__org_apache_commons_commons_lang3_3_0.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_core_8_0_23.xml b/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_core_8_0_23.xml
new file mode 100644
index 0000000..7e2d2eb
--- /dev/null
+++ b/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_core_8_0_23.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_el_8_0_23.xml b/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_el_8_0_23.xml
new file mode 100644
index 0000000..29f4076
--- /dev/null
+++ b/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_el_8_0_23.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_logging_juli_8_0_23.xml b/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_logging_juli_8_0_23.xml
new file mode 100644
index 0000000..8683ea2
--- /dev/null
+++ b/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_logging_juli_8_0_23.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_websocket_8_0_23.xml b/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_websocket_8_0_23.xml
new file mode 100644
index 0000000..0250d9a
--- /dev/null
+++ b/.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_websocket_8_0_23.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_tomcat_1_2_4_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_tomcat_1_2_4_RELEASE.xml
new file mode 100644
index 0000000..a28ccd7
--- /dev/null
+++ b/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_tomcat_1_2_4_RELEASE.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 3bb339b..288c081 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -2,8 +2,12 @@
+
+
+
+
@@ -32,19 +36,19 @@
-
-
+
+
-
+
-
-
+
+
@@ -52,15 +56,32 @@
-
-
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -68,13 +89,25 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -88,6 +121,7 @@
print
dns
+ split
@@ -102,9 +136,16 @@
@@ -116,7 +157,8 @@
DEFINITION_ORDER
-
+
+
@@ -136,6 +178,9 @@
+
+
+
@@ -154,6 +199,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -241,6 +354,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -628,14 +756,16 @@
-
+
+
-
+
-
+
+
@@ -653,12 +783,12 @@
-
+
-
+
@@ -670,19 +800,20 @@
-
+
+
-
+
@@ -694,12 +825,11 @@
-
+
-
@@ -742,8 +872,14 @@
-
-
+
+
+
+
+
+
+
+
@@ -762,10 +898,7 @@
-
-
-
-
+
@@ -811,10 +944,7 @@
-
-
-
-
+
@@ -849,10 +979,7 @@
-
-
-
-
+
@@ -876,10 +1003,7 @@
-
-
-
-
+
@@ -903,43 +1027,90 @@
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index e2a9403..22e87a1 100644
--- a/README.md
+++ b/README.md
@@ -23,9 +23,12 @@
合法URL返回true,非法URL返回false。
```java
-security urlCheck = new security();
+// URL白名单组件测试
+checkURL urlCheck = new checkURL();
String[] urlWList = {"joychou.com", "joychou.me"};
-Boolean ret = urlCheck.checkUrlWlist("http://test.joychou.me", urlWList);
+Boolean ret = urlCheck.checkUrlWlist("http://test.joychou.org", urlWList);
+System.out.println(ret);
+
```
## checkSSRF
@@ -45,11 +48,13 @@ Boolean ret = urlCheck.checkUrlWlist("http://test.joychou.me", urlWList);
URL只支持HTTP协议。
```java
-security urlCheck = new security();
+// SSRF组件测试
+SSRF check = new SSRF();
String url = "http://dns_rebind.joychou.me";
-ret = urlCheck.checkSSRF(url);
+ret = check.checkSSRF(url);
if (ret){
- // curl url
+ String con = Request.Get(url).execute().returnContent().toString();
+ System.out.println(con);
}
else {
System.out.println("Bad boy. The url is illegal");
@@ -59,9 +64,12 @@ else {
### 绕过姿势
-以上代码在设置TTL为0的情况,可以用以下方法绕过 :
+以上代码在设置TTL为0的情况,可以用DNS Rebinding绕过。
-1. DNS Rebind
-2. 域名解析2个A记录地址(分别为外网和内网)
+但是,只要Java不设置TTL为0,该代码逻辑上不存在被绕过风险。
+
+## 获取真实IP
+
+
+用这份代码,必须保证,前面Proxy有把真实IP放到X-Real-IP头。
-也就是说,只要Java不设置TTL为0,该代码逻辑上不存在被绕过风险。
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 37b2d20..6fe8c78 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,5 +21,27 @@
4.3.6
+
+
+ javax.servlet
+ servlet-api
+ 2.5
+ provided
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-tomcat
+ 1.2.4.RELEASE
+
+
+
+
+ org.apache.commons
+ commons-lang3
+ 3.0
+
+
\ No newline at end of file
diff --git a/src/main/java/IPAddress.java b/src/main/java/IPAddress.java
new file mode 100644
index 0000000..a4a484a
--- /dev/null
+++ b/src/main/java/IPAddress.java
@@ -0,0 +1,29 @@
+import org.apache.commons.lang3.StringUtils;
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * date: 17/9/14.
+ * author: JoyChou(https://joychou.org)
+ */
+
+public class IPAddress {
+ /**
+ * 从Header里的X-Real-IP获取IP地址,如果为空,取Remote_Addr
+ * @param request
+ * @return
+ */
+ public static String getIPFromRealIPHeader(HttpServletRequest request){
+ String ip = request.getHeader("X-Real-IP");
+ if (StringUtils.isNotBlank("ip")) {
+ return ip;
+ }else {
+ String remoteAddr = request.getRemoteAddr();
+ if (StringUtils.isNotBlank(remoteAddr)) {
+ return remoteAddr;
+ }
+ }
+ return "";
+ }
+
+
+}
diff --git a/src/main/java/security.java b/src/main/java/SSRF.java
similarity index 62%
rename from src/main/java/security.java
rename to src/main/java/SSRF.java
index e23c999..fd092eb 100644
--- a/src/main/java/security.java
+++ b/src/main/java/SSRF.java
@@ -1,72 +1,20 @@
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.InetAddress;
+import java.net.URL;
+
/**
* Author: JoyChou
* Mail: viarus#qq.com
* Date: 2017.09.05
*/
-import java.io.IOException;
-import java.net.HttpURLConnection;
-import java.net.InetAddress;
-import java.net.URL;
-import com.google.common.net.InternetDomainName;
-
-public class security {
-
- /*
- * 检测传入的URL是否在白名单的域名里
- * url:需要检测的URL
- * urlWList: 一级域名的域名列表,比如String[] urlWList = {"joychou.com", "joychou.me"};
- * 返回值:合法URL返回true,非法URL返回false
- */
- public static Boolean checkUrlWlist(String url, String[] urlWList) {
- try {
- URL u = new URL(url);
- // 只允许http和https的协议
- if (!u.getProtocol().startsWith("http") && !u.getProtocol().startsWith("https")) {
- return false;
- }
- // 获取域名,并转为小写
- String host = u.getHost().toLowerCase();
- // 获取一级域名
- String rootDomain = InternetDomainName.from(host).topPrivateDomain().toString();
-
- for (String whiteUrl: urlWList){
- if (rootDomain.equals(whiteUrl)) {
- return true;
- }
- }
- return false;
-
- } catch (Exception e) {
- return false;
- }
- }
-
-
- /*
- * 判断一个URL的IP是否是内网IP
- * 如果是内网IP,返回true
- * 非内网IP,返回false
- */
- public static boolean isInnerIpFromUrl(String url) throws Exception {
- String domain = getUrlDomain(url);
- if (domain.equals("")) {
- return true; // 异常URL当成内网IP等非法URL处理
- }
-
- String ip = DomainToIP(domain);
- if(ip.equals("")){
- return true; // 如果域名转换为IP异常,则认为是非法URL
- }
- return isInnerIp(ip);
- }
-
-
- /*
- * check SSRF (判断逻辑为判断URL的IP是否是内网IP)
- * 如果是内网IP,返回false,表示checkSSRF不通过。否则返回true。即合法返回true
- * URL只支持HTTP协议
- * 设置了访问超时时间为3s
+public class SSRF {
+ /**
+ * check SSRF (判断逻辑为判断URL的IP是否是内网IP)
+ * 如果是内网IP,返回false,表示checkSSRF不通过。否则返回true。即合法返回true
+ * URL只支持HTTP协议
+ * 设置了访问超时时间为3s
*/
public static Boolean checkSSRF(String url) {
@@ -103,13 +51,34 @@ public class security {
return true;
}
- /*
- 内网IP:
- 10.0.0.1 - 10.255.255.254 (10.0.0.0/8)
- 192.168.0.1 - 192.168.255.254 (192.168.0.0/16)
- 127.0.0.1 - 127.255.255.254 (127.0.0.0/8)
- 172.16.0.1 - 172.31.255.254 (172.16.0.0/12)
- */
+
+
+ /**
+ * 判断一个URL的IP是否是内网IP
+ * 如果是内网IP,返回true
+ * 非内网IP,返回false
+ */
+ public static boolean isInnerIpFromUrl(String url) throws Exception {
+ String domain = getUrlDomain(url);
+ if (domain.equals("")) {
+ return true; // 异常URL当成内网IP等非法URL处理
+ }
+
+ String ip = DomainToIP(domain);
+ if(ip.equals("")){
+ return true; // 如果域名转换为IP异常,则认为是非法URL
+ }
+ return isInnerIp(ip);
+ }
+
+
+ /**
+ * 内网IP:
+ * 10.0.0.1 - 10.255.255.254 (10.0.0.0/8)
+ * 192.168.0.1 - 192.168.255.254 (192.168.0.0/16)
+ * 127.0.0.1 - 127.255.255.254 (127.0.0.0/8)
+ * 172.16.0.1 - 172.31.255.254 (172.16.0.0/12)
+ */
public static boolean isInnerIp(String strIP) throws IOException {
try{
String[] ipArr = strIP.split("\\.");
@@ -128,12 +97,13 @@ public class security {
}
}
- /*
- * 域名转换为IP
- * 会将各种进制的ip转为正常ip
- * 167772161转换为10.0.0.1
- * 127.0.0.1.xip.io转换为127.0.0.1
- */
+
+ /**
+ * 域名转换为IP
+ * 会将各种进制的ip转为正常ip
+ * 167772161转换为10.0.0.1
+ * 127.0.0.1.xip.io转换为127.0.0.1
+ */
public static String DomainToIP(String domain) throws IOException{
try {
InetAddress IpAddress = InetAddress.getByName(domain); // send dns request
@@ -144,10 +114,10 @@ public class security {
}
}
- /*
- 从URL中获取域名
- 限制为http/https协议
- */
+ /**
+ * 从URL中获取域名
+ * 限制为http/https协议
+ */
public static String getUrlDomain(String url) throws IOException{
try {
URL u = new URL(url);
@@ -160,8 +130,4 @@ public class security {
}
}
-
- public static void main(String[] args) throws Exception {
-
- }
}
diff --git a/src/main/java/checkURL.java b/src/main/java/checkURL.java
new file mode 100644
index 0000000..a43c560
--- /dev/null
+++ b/src/main/java/checkURL.java
@@ -0,0 +1,51 @@
+/**
+ * Author: JoyChou
+ * Mail: viarus#qq.com
+ * Date: 2017.09.05
+ */
+
+
+import java.net.URL;
+import com.google.common.net.InternetDomainName;
+
+
+public class checkURL {
+
+ /**
+ * 检测传入的URL是否在白名单的域名里
+ * url:需要检测的URL
+ * urlWList: 一级域名的域名列表,比如String[] urlWList = {"joychou.com", "joychou.me"};
+ * 返回值:合法URL返回true,非法URL返回false
+ */
+ public static Boolean checkUrlWlist(String url, String[] urlWList) {
+ try {
+ URL u = new URL(url);
+ // 只允许http和https的协议
+ if (!u.getProtocol().startsWith("http") && !u.getProtocol().startsWith("https")) {
+ return false;
+ }
+ // 获取域名,并转为小写
+ String host = u.getHost().toLowerCase();
+ // 获取一级域名
+ String rootDomain = InternetDomainName.from(host).topPrivateDomain().toString();
+
+ for (String whiteUrl: urlWList){
+ if (rootDomain.equals(whiteUrl)) {
+ return true;
+ }
+ }
+ return false;
+
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+
+
+
+
+ public static void main(String[] args) throws Exception {
+
+ }
+}
diff --git a/src/main/java/test.java b/src/main/java/test.java
index 19cabc8..e5159ce 100644
--- a/src/main/java/test.java
+++ b/src/main/java/test.java
@@ -9,14 +9,15 @@ public class test {
public static void main(String[] args) throws Exception {
// URL白名单组件测试
- security urlCheck = new security();
+ checkURL urlCheck = new checkURL();
String[] urlWList = {"joychou.com", "joychou.me"};
Boolean ret = urlCheck.checkUrlWlist("http://test.joychou.org", urlWList);
System.out.println(ret);
// SSRF组件测试
+ SSRF check = new SSRF();
String url = "http://dns_rebind.joychou.me";
- ret = urlCheck.checkSSRF(url);
+ ret = check.checkSSRF(url);
if (ret){
String con = Request.Get(url).execute().returnContent().toString();
System.out.println(con);
@@ -24,5 +25,7 @@ public class test {
else {
System.out.println("Bad boy. The url is illegal");
}
+
+
}
}
diff --git a/target/classes/IPAddress.class b/target/classes/IPAddress.class
new file mode 100644
index 0000000..3ef8d64
Binary files /dev/null and b/target/classes/IPAddress.class differ
diff --git a/target/classes/ssrf.class b/target/classes/ssrf.class
new file mode 100644
index 0000000..aadcd8b
Binary files /dev/null and b/target/classes/ssrf.class differ
diff --git a/target/classes/test.class b/target/classes/test.class
new file mode 100644
index 0000000..f2102a2
Binary files /dev/null and b/target/classes/test.class differ
diff --git a/target/classes/url.class b/target/classes/url.class
new file mode 100644
index 0000000..d720be8
Binary files /dev/null and b/target/classes/url.class differ
diff --git a/trident.iml b/trident.iml
index 0f7d7fa..eacd736 100644
--- a/trident.iml
+++ b/trident.iml
@@ -17,5 +17,12 @@
+
+
+
+
+
+
+
\ No newline at end of file