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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -653,12 +783,12 @@ - + - @@ -670,19 +800,20 @@ - + + - + @@ -694,12 +825,11 @@ - + - @@ -742,8 +872,14 @@ - - + + + + + + + \ 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