spring 3.0 xss 공격 차단 전자정부프레임워크 filter 적용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
web.xml
easyframework.common.security.XSSFilter
</filter-class>
</filter>
</filter-mapping>
XSSFilter Class
public class XSSFilter implements Filter{
private FilterConfig config;
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
chain.doFilter(new HTMLTagFilterRequestWrapper((HttpServletRequest)request), response);
}
public void init(FilterConfig config) throws ServletException {
this.config = config;
}
public void destroy() {
}
}
HTMLTagFilterRequestWrapper Class
public class HTMLTagFilterRequestWrapper extends HttpServletRequestWrapper {
public HTMLTagFilterRequestWrapper(HttpServletRequest request) {
super(request);
}
public String[] getParameterValues(String parameter) {
String[] values = super.getParameterValues(parameter);
if (values == null) {
return null;
}
for (int i = 0; i < values.length; i++) {
if (values[i] != null) {
values[i] = EgovWebUtil.clearXSSMinimum(values[i]);
} else {
values[i] = null;
}
}
return values;
}
public String getParameter(String parameter) {
String value = super.getParameter(parameter);
if (value == null) {
return null;
}
value = EgovWebUtil.clearXSSMinimum(value);
return value;
}
}
WebUtil.class
public class EgovWebUtil {
@Value(“#{global[‘File.UploadMimeType’]}”)
private String UploadMimeType; // properties 에서 제외 UploadMimeType 가져오기.
public static String clearXSSMinimum(String value) {
| if (value == null | value.trim().equals(“”)) { |
return ””;
}
String returnValue = value;
returnValue = returnValue.replaceAll(“&”, ”&”);
returnValue = returnValue.replaceAll(“<”, ”<”);
returnValue = returnValue.replaceAll(“>”, ”>”);
returnValue = returnValue.replaceAll(“"”, ”"”);
returnValue = returnValue.replaceAll(“'”, ”'”);
returnValue = returnValue.replaceAll(“~!left!~”, ”<”);
returnValue = returnValue.replaceAll(“~!right!~”, ”>”);
return returnValue;
}
public static String clearXSSMaximum(String value) {
String returnValue = value;
returnValue = clearXSSMinimum(returnValue);
returnValue = returnValue.replaceAll(“%00”, null);
returnValue = returnValue.replaceAll(“%”, ”%”);
// \. => .
returnValue = returnValue.replaceAll(“\.\./”, ””); // ../
returnValue = returnValue.replaceAll(“\.\.\\”, ””); // ..\
returnValue = returnValue.replaceAll(“\./”, ””); // ./
returnValue = returnValue.replaceAll(“%2F”, ””);
return returnValue;
}
public static String filePathBlackList(String value) {
String returnValue = value;
| if (returnValue == null | returnValue.trim().equals(“”)) { |
return ””;
}
returnValue = returnValue.replaceAll(“\.\./”, ””); // ../
returnValue = returnValue.replaceAll(“\.\.\\”, ””); // ..\
return returnValue;
}
/* 행안부 보안취약점 점검 조치 방안. @param value @return /
public static String filePathReplaceAll(String value) {
String returnValue = value;
| if (returnValue == null | returnValue.trim().equals(“”)) { |
return ””;
}
returnValue = returnValue.replaceAll(“/”, ””);
returnValue = returnValue.replaceAll(“\”, ””);
returnValue = returnValue.replaceAll(“\.\.”, ””); // ..
returnValue = returnValue.replaceAll(“&”, ””);
return returnValue;
}
public static String filePathWhiteList(String value) {
return value; // TODO
}
public static boolean isIPAddress(String str) {
Pattern ipPattern = Pattern.compile(“\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}”);
return ipPattern.matcher(str).matches();
}
public static String removeCRLF(String parameter) {
return parameter.replaceAll(“\r”, ””).replaceAll(“\n”, ””);
}
public static String removeSQLInjectionRisk(String parameter) {
return parameter.replaceAll(“\p{Space}”, ””).replaceAll(“\*”, ””).replaceAll(“%”, ””)
.replaceAll(“;”, ””).replaceAll(“-“, ””).replaceAll(“\+”, ””).replaceAll(“,”, ””);
}
public static String removeOSCmdRisk(String parameter) {
| return parameter.replaceAll(“\p{Space}”, ””).replaceAll(“\*”, ””).replaceAll(“ | ”, ””).replaceAll(“;”, ””); |
}
//파일 MIME타입 확인
public static boolean isFileUpload(String mimetype)
{
boolean boo = false;
String excludeFile = EgovProperties.getProperty(“File.UploadMimeType”);
System.out.println(“ ::::::::::::::::::::::::::::::::::> ” + excludeFile);
String [] excludeUrlArray= excludeFile.split(“,”);
int length = excludeUrlArray.length;
for(int i=0; i<length; i++){
if(excludeUrlArray[i].indexOf(mimetype) > -1){
boo=true;
}
}
System.out.println(“——————–> boo : ” + boo);
return boo;
}
/* public static void main(String[] args) {
String test = null; test = ”<script language=’javascript’ encoding="utf-8">q&a</script>”;
System.out.println(“clearXSSMinimum() Test”); System.out.println(test);
System.out.println(“=>”); System.out.println(clearXSSMinimum(test));
System.out.println(); test = ”/a/b/c../..\”; System.out.println(“clearXSSMaximum() Test”);
System.out.println(test); System.out.println(“ =>”); System.out.println(clearXSSMaximum(test));
System.out.println(); test = ”/a/b/c/../../../..\..\”; System.out.println(“filePathBlackList() Test”);
System.out.println(test); System.out.println(“=>”); System.out.println(filePathBlackList(test)); System.out.println();
test = ”192.168.0.1”; System.out.println(“isIPAddress() test”); System.out.println(“IP : ” + test + ” => ” + isIPAddress(test));
test = ”abc def*%;-+,ghi”; System.out.println(“removeSQLInjectionRisk() test”); System.out.println(test + ” => ” + removeSQLInjectionRisk(test));
} //*/
}
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ 2015.08.03 ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
현대에서 able framework에다가 적용해보니 잘 안되서 찾다보니 해결책을 알게되었다.
그래서 공유하게 되었다.
Tomcat6에서 Spring 3 의 MultipartFile 처리시 Servlet 버전의 차이로 인해 이슈가 발생할 수 있다.
[원인]
문제의 발단을 이렇습니다.
chrome의 RestConsole app을 이용하여 file upload를 테스트 하려는데
다음과 같은 error 가 발생했습니다.
[2012.07.11 09:38:50.251][DEBUG][o.s.w.m.support.MultipartFilter] Resolving multipart request [/master/api/v1/device-platforms/6698/images/ICON] with MultipartFilter**7월 11, 2012 9:38:50 오전 org.apache.catalina.core.StandardWrapperValve invoke 심각: Servlet.service() for servlet dispatcher threw exception java.lang.NoSuchMethodError: javax.servlet.http.HttpServletRequest.getParts()Ljava/util/Collection; at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.
MultipartFilter에서 file을 처리하다가 HttpServletRequest의 getParts() 메소드를 호출하는데
그런 메소드는 없다는 거죠..
[결론]**
web.xml 에 다음과 같은 설정이 있습니다.
multipartFilter org.springframework.web.multipart.support.MultipartFilter multipartResolverBeanName multipartResolver multipartFilter /* MultipartFilter를 사용하겠다는 것이고요.
이 클래스는 default로 filterMultipartResolver bean을 찾는데
대신 multipartResolver를 찾아라 라는 설정입니다.
빈 등록은 다음과 같습니다.
근데 에러메세지를 보면 CommonsMultipartResolver가 아닌 StandardServletMultipartResolver를 쓰고 있네요.
API를 보면 다음과 같은 내용이 있습니다.
Looks up the MultipartResolver on each request, to avoid initialization order issues (when using ContextLoaderServlet, the root application context will get initialized after*** this filter).
ContextLoaderServlet은 ContextLoaderListener의 예전 버전이라 할수 있죠.
프로젝트에서는 classpath:dispatcherServlet.xml 하나로 설정을 다 하고 있어서.
ContextLoaderListener를 쓰지 않았습니다.
다음을 추가 했습니다.
contextConfigLocation classpath:dispatcherServlet.xml ContextLoader org.springframework.web.context.ContextLoaderListener 삽질이 궁금하시다면 ~
[문제 해결 과정]
검색-
getParts() 메소드는 servlet-api 3.0 에서 지원되는 메소드네요.
pom.xml에 servlet-api 3.0 을 넣어줬습니다.
같은 에러~
tomcat 라이브러리를 쓰니까 연결이 안되는 것인가?
검색-
tomcat6는 servlet-api 2.5 , tomcat7는 servlet-api 3.0
spring 3.0.7은 servlet-api 2.5 기반 , spring 3.1.1은 tomcat7 기반
어라? 3.1.1은 tomcat7기반인데 왜 tomcat6를 쓰지?
이슈제기-
store 에서는 잘 되고 있다는 박병주 책임님의 제보-
어떻게??
Spring doc 분석 -
StandardServletMultipartResolver 는 servlet 3 를 사용한다.
CommonsMultipartResolver 를 bean으로 등록했다
MultipartFilter 는 왜 CommonsMultipartResolver를 찾지 못하는가?
api 분석 -
아하!! ContextLoader가 필요하구나
ref
http://mvnrepository.com/artifact/org.springframework/spring-webmvc/3.1.1.RELEASE
http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/mvc.html#mvc-multipart-resolver-commons ——————————— 2015.08.04 —————————————-
추가된 내용.
문제는 위 내용대로 적용하면 filter는 걸린다 하지만. multiRequest 에 파일이 안따라 온다는거 ㅡㅡ;
따라서
부분에서
삭제해주고 multipartRequest 가 등록되어있는 bean로 이동하여
id 값을 filterMultipartResolver 로 변경시켜야 한다.
그럼 해결됨