XSS(Cross Site Scripting) Filtering

송준희·2021년 4월 28일
0

Back

목록 보기
2/7

나쁜 사용자들이 request에 js 코드를 담아서 서버로 전송하고 이 값이 저장되면
이상한 페이지로 이동하거나 alert 창이 뜨는 등 서비스에 문제가 생길 수 있다.
예를 들어 request에

<script>location.href="https://www.naver.com"</script>

를 담아 서버에 전송하고 이 값이 그대로 db에 저장되면
다음 번에 다시 이 페이지를 불러올 때 위의 script 문이 실행되어 www.naver.com 으로 이동하게 된다.


이런 악의적인 공격을 막기 위해선 클라이언트가 전송한 데이터를 서버에서 확인해야 한다.
https://github.com/naver/lucy-xss-filter 에서 제공하는 Filter를 이용하는 방법이 구글에 많이 나왔지만 지금은 사용할 수 없는 것 같다.
Filter와 HttpServletRequestWrapper을 상속받아 특수문자를 ascii 코드(?)로 파싱하는 방식이 있는데
구글에 검색하면 많은 자료들이 나온다.
파싱하는 코드의 일부를 살펴보면 다음과 같다.

  for (int j = 0; j < value.length(); ++j) {
                char c = value.charAt(j);
                switch (c) {
                case '<':
                    strBuff.append("&lt;");
                    break;
                case '&':
                    strBuff.append("&amp;");
                    break;
                    
                    .
                    .
                    .
                    
                case '(':
                    strBuff.append("&#40;");
                    break;
                default:
                    strBuff.append(c);
                }
            }

일반적으로 Filter와 HttpServletRequestWrapper만 적용하면 XSS를 막을 수 있지만
form 타입이 enctype="multipart/form-data"인 경우 이 방법이 제대로 작동하지 않았다.
첨부파일이 없는 경우 HttpServletRequestWrapper의 getParameterValues(), getParameter()를 이용하여
request에 담긴 데이터를 파싱하지만
첨부파일이 있는 경우 데이터를 읽을 때 getPart(), getParts() 메서드를 사용해서 읽어야 하는데
HttpServletRequestWrapper에는 이러한 메서드가 없기 때문에 파싱할 수 없다고 한다.


해결방법은 web.xml, servlet-context.xml, tomcat의 context.xml을 수정하면 된다.

먼저 web.xml 파일에서
spring framework에서 제공하는 CharacerEncodingFilter와 기존에 사용한 Filter 사이에
spring framework에서 제공하는 MultipartFilter를 추가한다.

  <filter>
      <filter-name>MultipartFilter</filter-name>
      <filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
  </filter>
  <filter-mapping>
      <filter-name>MultipartFilter</filter-name>
      <url-pattern>/*</url-pattern>
  </filter-mapping>

다음으로 servlet-context.xml에 bean을 추가한다.

<beans:bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
	<beans:property name="defaultEncoding" value="UTF-8"/>
	<beans:property name="maxUploadSize" value="40960000"/>
</beans:bean>
// servlet 버전이 3.0라면 id를 multipartResolver
// servlet 버전이 2.5라면 id를 filterMultipartResolver

마지막으로 웹서버가 실행되는 tomcat 서버의 context.xml 파일을 수정해야 한다.
기존 context.xml은 다음과 같다.

<Context>
    <WatchedResource>WEB-INF/web.xml</WatchedResource>
    <WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
</Context>

여기서 Context 부분을 아래와 같이 수정하면 된다.

<Context allowCasualMultipartParsing="true" path="/">
    <WatchedResource>WEB-INF/web.xml</WatchedResource>			// 없어도 됨
    <WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>	// 없어도 됨
</Context>

이제 클라이언트가 request에 `XSS`를 담아 서버로 전송하면
서버는 이 값을 XSS<script>alert("HI");</script>로 파싱하므로 XSS 공격을 막을 수 있다.


HttpServletRequestWrapper 클래스는 ServletRequestWrapper 클래스를 상속받는다.
ServletRequestWrapper 클래스에는 getParameter(), getParameterMap(), getParameterNames(), getParameterValues() 등의 메서드가 있는데
호출할 메서드의 parameter에 따라서 필요한 메서드를 재정의해줘야 한다.
parameter가 일반 dto class라면 getParameterValues()만 재정의하면 되지만
parameter로 Map을 받는다면 getParameterMap()을 재정의해줘야 한다.

profile
오늘 달리면 내일 걸을 수 있다!

0개의 댓글