Skip to content

Commit fa48bad

Browse files
committed
增加socket hook模块 实现socket层拦截SSRF
1 parent 33748f3 commit fa48bad

File tree

6 files changed

+463
-1
lines changed

6 files changed

+463
-1
lines changed

src/main/java/org/joychou/security/SSRFChecker.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import java.net.URI;
66
import java.net.URL;
77
import java.util.ArrayList;
8+
import java.util.regex.Matcher;
9+
import java.util.regex.Pattern;
810

911
import org.apache.commons.net.util.SubnetUtils;
1012
import org.joychou.config.WebConfig;
@@ -14,6 +16,7 @@
1416
class SSRFChecker {
1517

1618
private static Logger logger = LoggerFactory.getLogger(SSRFChecker.class);
19+
private final static Pattern IP_PATTERN = Pattern.compile("((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)");
1720

1821
static boolean checkURLFckSSRF(String url) {
1922
if (null == url){
@@ -122,7 +125,7 @@ static boolean isInnerIPByUrl(String url) {
122125
* @param strIP ip字符串
123126
* @return 如果是内网ip,返回true,否则返回false。
124127
*/
125-
private static boolean isInnerIp(String strIP){
128+
static boolean isInnerIp(String strIP){
126129

127130
ArrayList<String> blackSubnets= WebConfig.getSsrfBlockIps();
128131

@@ -176,4 +179,14 @@ private static String url2host(String url) {
176179
}
177180

178181
}
182+
183+
/**
184+
* 匹配ip
185+
* @return
186+
*/
187+
static String getIpFromStr(String ipStr){
188+
Matcher matcher = IP_PATTERN.matcher(ipStr);
189+
System.out.println(matcher.find());
190+
return matcher.group();
191+
}
179192
}

src/main/java/org/joychou/security/SecurityUtil.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import org.slf4j.Logger;
55
import org.slf4j.LoggerFactory;
66

7+
import java.io.IOException;
78
import java.io.UnsupportedEncodingException;
89
import java.net.URI;
910
import java.net.URLDecoder;
@@ -118,6 +119,29 @@ public static boolean checkSSRFWithoutRedirect(String url) {
118119
return !SSRFChecker.isInnerIPByUrl(url);
119120
}
120121

122+
/**
123+
* @Author liergou
124+
* @Description 基于Socket hook 进行SSRF检测拦截
125+
* @Date 2:15 2020/4/4
126+
* @Param []
127+
* @return void
128+
**/
129+
public static void startSSRFHook() throws NoSuchFieldException, IOException {
130+
SocketHook.startHook();
131+
}
132+
133+
/**
134+
* @Author liergou
135+
* @Description 关闭Socket hook
136+
* @Date 2:15 2020/4/4
137+
* @Param []
138+
* @return void
139+
**/
140+
public static void stopSSRFHook(){
141+
SocketHook.stopHook();
142+
}
143+
144+
121145

122146
/**
123147
* Filter file path to prevent path traversal vulns.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package org.joychou.security;
2+
3+
import java.io.IOException;
4+
import java.net.Socket;
5+
import java.net.SocketException;
6+
7+
/**
8+
* @Author liergou
9+
* @Description Socket hook开关自如
10+
* @Date 2:12 2020/4/4
11+
**/
12+
class SocketHook {
13+
static void startHook() throws NoSuchFieldException, IOException {
14+
SocketHookFactory.initSocket();
15+
SocketHookFactory.setHook(true);
16+
try{
17+
Socket.setSocketImplFactory(new SocketHookFactory());
18+
}catch (SocketException ignored){
19+
}
20+
}
21+
22+
static void stopHook(){
23+
SocketHookFactory.setHook(false);
24+
}
25+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package org.joychou.security;
2+
3+
4+
import java.io.IOException;
5+
import java.lang.reflect.Field;
6+
import java.net.Socket;
7+
import java.net.SocketImpl;
8+
import java.net.SocketImplFactory;
9+
import java.util.logging.Level;
10+
import java.util.logging.Logger;
11+
12+
13+
/**
14+
* @Author liergou
15+
* @Description socket factory impl
16+
* @Date 23:41 2020/4/3
17+
* @Param
18+
* @return
19+
**/
20+
public class SocketHookFactory implements SocketImplFactory
21+
{
22+
private static SocketImpl clazz;
23+
private static Boolean isHook = false;
24+
25+
/**
26+
* @Author liergou
27+
* @Description switch hook
28+
* @Date 23:42 2020/4/2
29+
* @Param [set]
30+
* @return void
31+
**/
32+
public static void setHook(Boolean set){
33+
isHook = set;
34+
}
35+
36+
/**
37+
* @Author liergou
38+
* @Description 初始化
39+
* @Date 23:42 2020/4/2
40+
* @Param []
41+
* @return void
42+
**/
43+
public static synchronized void initSocket() throws NoSuchFieldException {
44+
if ( clazz != null ) { return; }
45+
46+
Socket socket = new Socket();
47+
try{
48+
Field implField = Socket.class.getDeclaredField("impl");
49+
implField.setAccessible( true );
50+
clazz = (SocketImpl) implField.get(socket);
51+
}catch (NoSuchFieldException | IllegalAccessException e){
52+
throw new RuntimeException("SocketHookFactory init failed!");
53+
}
54+
55+
try {
56+
socket.close();
57+
}
58+
catch ( IOException ignored)
59+
{
60+
61+
}
62+
}
63+
64+
public SocketImpl createSocketImpl() {
65+
66+
if(isHook) {
67+
try {
68+
return new SocketHookImpl(clazz);
69+
} catch (Exception e) {
70+
Logger.getLogger(SocketHookFactory.class.getName()).log(Level.WARNING, "hook 失败 请检查" );
71+
return clazz;
72+
}
73+
}else{
74+
return clazz;
75+
}
76+
}
77+
}

0 commit comments

Comments
 (0)