add checkSSRF

This commit is contained in:
JoyChou
2017-09-05 20:51:25 +08:00
parent c7f1291eb2
commit f65a696286
5 changed files with 148 additions and 18 deletions

35
.idea/workspace.xml generated
View File

@@ -2,7 +2,6 @@
<project version="4"> <project version="4">
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="42982c84-cdb2-4596-b4aa-818c31fc199a" name="Default" comment=""> <list default="true" id="42982c84-cdb2-4596-b4aa-818c31fc199a" name="Default" comment="">
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/.idea/workspace.xml" afterPath="$PROJECT_DIR$/.idea/workspace.xml" />
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/main/java/security.java" afterPath="$PROJECT_DIR$/src/main/java/security.java" /> <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/main/java/security.java" afterPath="$PROJECT_DIR$/src/main/java/security.java" />
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/main/java/test.java" afterPath="$PROJECT_DIR$/src/main/java/test.java" /> <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/main/java/test.java" afterPath="$PROJECT_DIR$/src/main/java/test.java" />
</list> </list>
@@ -23,7 +22,9 @@
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="289"> <state relative-caret-position="289">
<caret line="17" column="10" lean-forward="false" selection-start-line="17" selection-start-column="10" selection-end-line="17" selection-end-column="10" /> <caret line="17" column="10" lean-forward="false" selection-start-line="17" selection-start-column="10" selection-end-line="17" selection-end-column="10" />
<folding /> <folding>
<marker date="1504604535000" expanded="true" signature="89:618" ph="..." />
</folding>
</state> </state>
</provider> </provider>
</entry> </entry>
@@ -44,8 +45,8 @@
<file leaf-file-name="security.java" pinned="false" current-in-tab="true"> <file leaf-file-name="security.java" pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/src/main/java/security.java"> <entry file="file://$PROJECT_DIR$/src/main/java/security.java">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="163"> <state relative-caret-position="276">
<caret line="10" column="0" lean-forward="true" selection-start-line="10" selection-start-column="0" selection-end-line="10" selection-end-column="0" /> <caret line="66" column="59" lean-forward="false" selection-start-line="66" selection-start-column="59" selection-end-line="66" selection-end-column="59" />
<folding> <folding>
<element signature="n#!!doc" expanded="true" /> <element signature="n#!!doc" expanded="true" />
<element signature="imports" expanded="true" /> <element signature="imports" expanded="true" />
@@ -57,8 +58,8 @@
<file leaf-file-name="test.java" pinned="false" current-in-tab="false"> <file leaf-file-name="test.java" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/src/main/java/test.java"> <entry file="file://$PROJECT_DIR$/src/main/java/test.java">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="238"> <state relative-caret-position="289">
<caret line="14" column="0" lean-forward="true" selection-start-line="14" selection-start-column="0" selection-end-line="14" selection-end-column="0" /> <caret line="17" column="50" lean-forward="false" selection-start-line="17" selection-start-column="50" selection-end-line="17" selection-end-column="50" />
<folding /> <folding />
</state> </state>
</provider> </provider>
@@ -87,8 +88,8 @@
<option value="$PROJECT_DIR$/pom.xml" /> <option value="$PROJECT_DIR$/pom.xml" />
<option value="$PROJECT_DIR$/src/main/java/main.java" /> <option value="$PROJECT_DIR$/src/main/java/main.java" />
<option value="$PROJECT_DIR$/README.md" /> <option value="$PROJECT_DIR$/README.md" />
<option value="$PROJECT_DIR$/src/main/java/security.java" />
<option value="$PROJECT_DIR$/src/main/java/test.java" /> <option value="$PROJECT_DIR$/src/main/java/test.java" />
<option value="$PROJECT_DIR$/src/main/java/security.java" />
</list> </list>
</option> </option>
</component> </component>
@@ -99,8 +100,6 @@
<sorting>DEFINITION_ORDER</sorting> <sorting>DEFINITION_ORDER</sorting>
</component> </component>
<component name="ProjectFrameBounds"> <component name="ProjectFrameBounds">
<option name="x" value="-1280" />
<option name="y" value="214" />
<option name="width" value="1280" /> <option name="width" value="1280" />
<option name="height" value="800" /> <option name="height" value="800" />
</component> </component>
@@ -658,15 +657,15 @@
<option name="number" value="Default" /> <option name="number" value="Default" />
<option name="presentableId" value="Default" /> <option name="presentableId" value="Default" />
<updated>1504604417100</updated> <updated>1504604417100</updated>
<workItem from="1504604422158" duration="2421000" /> <workItem from="1504604422158" duration="3470000" />
</task> </task>
<servers /> <servers />
</component> </component>
<component name="TimeTrackingManager"> <component name="TimeTrackingManager">
<option name="totallyTimeSpent" value="2421000" /> <option name="totallyTimeSpent" value="3470000" />
</component> </component>
<component name="ToolWindowManager"> <component name="ToolWindowManager">
<frame x="-1280" y="214" width="1280" height="800" extended-state="6" /> <frame x="0" y="0" width="1280" height="800" extended-state="0" />
<editor active="true" /> <editor active="true" />
<layout> <layout>
<window_info id="Palette" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" /> <window_info id="Palette" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
@@ -750,7 +749,9 @@
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="289"> <state relative-caret-position="289">
<caret line="17" column="10" lean-forward="false" selection-start-line="17" selection-start-column="10" selection-end-line="17" selection-end-column="10" /> <caret line="17" column="10" lean-forward="false" selection-start-line="17" selection-start-column="10" selection-end-line="17" selection-end-column="10" />
<folding /> <folding>
<marker date="1504604535000" expanded="true" signature="89:618" ph="..." />
</folding>
</state> </state>
</provider> </provider>
</entry> </entry>
@@ -775,16 +776,16 @@
</entry> </entry>
<entry file="file://$PROJECT_DIR$/src/main/java/test.java"> <entry file="file://$PROJECT_DIR$/src/main/java/test.java">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="238"> <state relative-caret-position="289">
<caret line="14" column="0" lean-forward="true" selection-start-line="14" selection-start-column="0" selection-end-line="14" selection-end-column="0" /> <caret line="17" column="50" lean-forward="false" selection-start-line="17" selection-start-column="50" selection-end-line="17" selection-end-column="50" />
<folding /> <folding />
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/src/main/java/security.java"> <entry file="file://$PROJECT_DIR$/src/main/java/security.java">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="163"> <state relative-caret-position="276">
<caret line="10" column="0" lean-forward="true" selection-start-line="10" selection-start-column="0" selection-end-line="10" selection-end-column="0" /> <caret line="66" column="59" lean-forward="false" selection-start-line="66" selection-start-column="59" selection-end-line="66" selection-end-column="59" />
<folding> <folding>
<element signature="n#!!doc" expanded="true" /> <element signature="n#!!doc" expanded="true" />
<element signature="imports" expanded="true" /> <element signature="imports" expanded="true" />

View File

@@ -4,6 +4,9 @@
* Date: 2017.09.05 * Date: 2017.09.05
*/ */
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.URL; import java.net.URL;
import com.google.common.net.InternetDomainName; import com.google.common.net.InternetDomainName;
@@ -13,7 +16,7 @@ public class security {
* 检测传入的URL是否在白名单的域名里 * 检测传入的URL是否在白名单的域名里
* url需要检测的URL * url需要检测的URL
* urlWList: 一级域名的域名列表比如String[] urlWList = {"joychou.com", "joychou.me"}; * urlWList: 一级域名的域名列表比如String[] urlWList = {"joychou.com", "joychou.me"};
* 合法URL返回true非法URL返回false * 返回值:合法URL返回true非法URL返回false
*/ */
public static Boolean checkUrlWlist(String url, String[] urlWList) { public static Boolean checkUrlWlist(String url, String[] urlWList) {
try { try {
@@ -39,6 +42,125 @@ public class security {
} }
} }
/*
* 判断一个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 static Boolean checkSSRF(String url) {
HttpURLConnection connection;
String finalUrl = url;
try {
do {
// 判断当前请求的URL是否是内网ip
Boolean bRet = isInnerIpFromUrl(finalUrl);
if (bRet) {
return true;
}
connection = (HttpURLConnection) new URL(finalUrl).openConnection();
connection.setInstanceFollowRedirects(false);
connection.setUseCaches(false); // 设置为false手动处理跳转可以拿到每个跳转的URL
connection.setConnectTimeout(3*1000); // 设置连接超时时间为3s
//connection.setRequestMethod("GET");
connection.connect(); // 会解析dns
int responseCode = connection.getResponseCode(); // 发起网络请求
if (responseCode >= 300 && responseCode < 400) {
String redirectedUrl = connection.getHeaderField("Location");
if (null == redirectedUrl)
break;
finalUrl = redirectedUrl;
System.out.println("redirected url: " + finalUrl);
} else
break;
} while (connection.getResponseCode() != HttpURLConnection.HTTP_OK);
connection.disconnect();
} catch (Exception e) {
return false;
}
return false;
}
/*
内网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("\\.");
if (ipArr.length != 4){
return false;
}
int ip_split1 = Integer.parseInt(ipArr[1]);
return (ipArr[0].equals("10") ||
ipArr[0].equals("127") ||
(ipArr[0].equals("172") && ip_split1 >= 16 && ip_split1 <=31) ||
(ipArr[0].equals("192") && ipArr[1].equals("168")));
}catch (Exception e) {
return false;
}
}
/*
* 域名转换为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);
return IpAddress.getHostAddress();
}
catch (Exception e) {
return "";
}
}
/*
从URL中获取域名
限制为http/https协议
*/
public static String getUrlDomain(String url) throws IOException{
try {
URL u = new URL(url);
if (!u.getProtocol().startsWith("http") && !u.getProtocol().startsWith("https")) {
throw new IOException("Protocol error: " + u.getProtocol());
}
return u.getHost();
} catch (Exception e) {
return "";
}
}
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
} }

View File

@@ -6,9 +6,16 @@
public class test { public class test {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
// URL白名单组件测试
security checkUrl = new security(); security checkUrl = new security();
String[] urlWList = {"joychou.com", "joychou.me"}; String[] urlWList = {"joychou.com", "joychou.me"};
Boolean ret = checkUrl.checkUrlWlist("http://test.joychou.me", urlWList); Boolean ret = checkUrl.checkUrlWlist("http://test.joychou.me", urlWList);
System.out.println(ret); System.out.println(ret);
// SSRF组件测试
ret = checkUrl.checkSSRF("http://127.0.0.1");
System.out.println(ret);
} }
} }

Binary file not shown.

Binary file not shown.