안녕하세요, 많이 늦었지만 새해 복 많이 받으세요. ^^
오늘 조언을 듣고 싶은 분야는 다름이 아니라 HandlerInterceptor 입니다.
제가 개발한 app에 대해서 고객사에서 보안검증 심사를 하신다고 하는데, 그 중 크로스 서버 스크립팅 공격의 취약점도 확인하신다고 하더라구요.
그래서 가장 빨리 해당 내용을 적용할 방법이 없을까 하다가 HandlerInterceptor가 생각이 나서 적용을 해 보았습니다.(이런 부분이 생길때 마다 스프링을 쓰길 잘했다는 생각이 듭니다. 물론 다른 잘 만든 프레임웍으로도 가능한 부분이긴 하겠지만요)
머릿속에 그린 시나리오는 request 객채에서 input, textarea 등으로 넘어져 오는 값에서 유효하지 않은 단어가 포함된 경우 그것을 Exception으로 처리하도록 하는 간단한 방법으로 그려 보았습니다.
먼저 적용대상은 SimpleUrlHandlerMapping으로 등록된 것들을 대상으로 Interceptor를 걸도록 했습니다.
<bean id="simpleUrlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="interceptors">
<list>
<ref local="xssHandlerInterceptor" />
</list>
</property>
<property name="order">
<value>0</value>
</property>
<property name="mappings">
<props>
<prop key="/index.htm">indexController</prop>
...
</props>
</property>
</bean>
그리고 HandlerInterceptor은 다음과 같이 정의 했습니다.
<bean id="xssHandlerInterceptor" class="kr.co.inogard.dtia.controller.interceptor.XSSHandlerInterceptor">
<property name="invaildWordMappings">
<props>
<prop key="javascript">javascript</prop>
<prop key="document">document.</prop>
<prop key="alert">alert(</prop>
</props>
</property>
</bean>
property에 유효하지 않은 단어를 미리 등록해 놓고, 입력값과 비교하는 방법으로 진행하려고 했습니다.
다음은 실제 소스 입니다.
import java.util.Enumeration;
import java.util.Properties;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import kr.co.inogard.dtia.utils.StringUtil;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
/**
*
*<ul>
* <li>프 로 그 램 : XSSHandlerInterceptor.java</li>
* <li>프로그램설명 : 크로스 서버 스크립팅(XSS) 공격 방지용 필터</li>
* <li>관련프로그램 : </li>
* <li>관련 테이블 : </li>
* <li>작 성 일 자 : 2010. 01. 20</li>
* <li>수 정 내 역 : </li>
* <li>참 고 사 항 : </li>
* </ul>
* @author 선영욱
*/
public class XSSHandlerInterceptor extends HandlerInterceptorAdapter {
private Properties invaildWordMappings;
public void setInvaildWordMappings(Properties invaildWordMappings) {
this.invaildWordMappings = invaildWordMappings;
}
/**
* 전처리
* @param request
* @param response
* @param handler
* @return
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
for(Enumeration names = request.getParameterNames(); names.hasMoreElements();) {
String name = (String)names.nextElement();
String val = StringUtil.nvl(request.getParameter(name));
String ret = getMatchInvaildWord(val);
if(null != ret){
String message = name+" 항목에 유효하지 않은 단어("+ret+")가 포함되어 크로스 서버 스크립팅(XSS)검사에 실패하였습니다.";
Exception e = new RuntimeException(message);
request.setAttribute("error", e);
request.setAttribute("uri", request.getRequestURI());
request.setAttribute("message", message);
request.setAttribute("exception_type", "RuntimeException");
throw e;
}
}
return true;
}
/**
* 유효하지 않은 단어가 포함되었는지 확인
* @param val
* @return
*/
public boolean existInvaildWord(String val) throws Exception {
boolean existInvaildWord = false;
if(null != getMatchInvaildWord(val)){
existInvaildWord = true;
}
return existInvaildWord;
}
/**
* 유효하지 않은 단어가 포함되었다면 어떤 단어인지 반환
* @param val
* @return
*/
public String getMatchInvaildWord(String val) throws Exception {
for(Enumeration names = invaildWordMappings.propertyNames(); names.hasMoreElements();) {
String key = (String) names.nextElement();
String invaildWord = invaildWordMappings.getProperty(key);
if(val.indexOf(invaildWord) > -1){
return invaildWord;
}
}
return null;
}
}
이런 방법으로 처리를 해서 테스트를 해 보았는데요, 원하는 대로 동작은 하는 것 같습니다.
하지만 이런 상황에서 적절한(성능, 또는 기타 다른 부분을 놓친 것이 있는 것 같아서요.)지 다른 분들의 조언을 듣고 싶습니다.
긴 글 읽어주셔서 감사합니다.
오늘도 좋은 하루 되세요. ^^