lucy-xss-servlet-filter를 사용하여 XSS 공격 방어하기

sarah·2022년 12월 17일
1

xss

목록 보기
2/3
💡 이전 글은 lucy-xss-filter를 사용하여 xss 공격을 방어하는 방법을 알아보았는데, 이번엔 servlet filter 에 추가하여 모든 요청 파라미터를 검사하도록 설정하였습니다. lucy-xss-filter와 다른 점 위주로 설명할 예정입니다.

1. lucy-xss-servlet-filter를 적용한 이유

lucy-xss-filter의 한계

  • 필요한 곳에 XSS 방어코드 누락
  • 불필요한 곳에 XSS 방어코드가 적용되는 경우
  • 여기저기 XSS 방어코드가 혼재되어 유지보수 비용 증가

⇒ 이러한 이유로 lucy-xss-servlet-filter를 적용하면 웹어플리케이션으로 들어오는 모든 요청 파라메터에 대해 기본적으로 XSS 방어 필터링을 수행가능하다.

⇒ 또한 lucy-xss-servlet-filter는 아래와 같은 방법 필터링 설정을 추가할 수 있다.

  • 설정한 url 필터링 제외
  • 설정한 prefix로 시작하는 파라메터 필터링 제외
  • 설정한 파라메터 필터링 제외

lucy-xss-servlet-filter의 장단점

  • XML 설정 만으로 XSS 방어가 가능해짐
  • 비지니스 레이어의 코드 수정이 발생하지 않음
  • 개발자가 XSS 방어를 신경 쓰지 않아도 됨
  • XSS 방어가 누락되지 않음
  • 설정 파일 하나로 XSS 방어절차가 파악됨
  • 파라메터명에 대해 관리가 필요해짐
  • 일괄 적용되어 영향 받기 때문에 정확한 필터링 룰 정의가 중요함
💡 [lucy-xss-sevlet-filter 사용시 주의 할 점]
신규로 개발하는 서비스에는 lucy-xss-servlet-filter를 사용하는 것을 추천하지만, 기존 잘 운영되는 시스템에 lucy-xss-servlet-filter를 사용하는 것은 추천하지 않습니다. 입력 파라메터가 전부 필터링 되기 때문에 서비스가 잘 동작하지 않는 의도치 않은 결과가 발생할 수 있기 때문입니다.

기존 시스템에 적용하시려면 lucy-xss-filter를 사용해 개발자가 일일히 필터링 하는 방식을 추천드립니다. 하지만 이 방법은 개발자의 집중력를 믿어야 하기 때문에 언젠가는 뚫릴 수 밖에 없는 방식입니다. 그렇기 때문에 시간을 충분히 확보하실 수 있으시거나 기존에 서블릿 필터 기반으로 XSS 공격을 방어하셨다면 이번 기회에 lucy-xss-servlet-filter를 적용해 XSS 공격에서 해방되시는 걸 추천드립니다.

2. lucy-xss-serlvet-filter 사용법

1. pom.xml 추가

<dependency>
	<groupId>com.navercorp.lucy</groupId>
	<artifactId>lucy-xss-servlet</artifactId>
	<version>2.0.0</version>
</dependency>

2. web.xml 추가

<filter>
	<filter-name>xssEscapeServletFilter</filter-name>
	<filter-class>com.navercorp.lucy.security.xss.servletfilter.XssEscapeServletFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>xssEscapeServletFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<!-- xssEscapeServletFilter는 CharacterEncodingFilter 뒤에 위치해야 한다. -->
<filter>
	<filter-name>encodingFilter</filter-name>
	<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
	<init-param>
		<param-name>encoding</param-name>
		<param-value>UTF-8</param-value>
	</init-param>
</filter>
<filter-mapping>
	<filter-name>encodingFilter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

<filter>
	<filter-name>xssEscapeServletFilter</filter-name>
	<filter-class>com.navercorp.lucy.security.xss.servletfilter.XssEscapeServletFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>xssEscapeServletFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

3. /resource 폴더 내에 "lucy-xss-servlet-filter-rule.xml" 파일을 생성

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns="http://www.navercorp.com/lucy-xss-servlet">
   <defenders>
       <!-- XssPreventer 등록 -->
       <defender>
           <name>xssPreventerDefender</name>
           <class>com.navercorp.lucy.security.xss.servletfilter.defender.XssPreventerDefender</class>
       </defender>

       <!-- XssSaxFilter 등록 -->
       <defender>
           <name>xssSaxFilterDefender</name>
           <class>com.navercorp.lucy.security.xss.servletfilter.defender.XssSaxFilterDefender</class>
           <init-param>
               <param-value>lucy-xss-sax.xml</param-value>   <!-- lucy-xss-filter의 sax용 설정파일 -->
               <param-value>false</param-value>        <!-- 필터링된 코멘트를 남길지 여부, 성능 효율상 false 추천 -->
           </init-param>
       </defender>

       <!-- XssFilter 등록 -->
       <defender>
           <name>xssFilterDefender</name>
           <class>com.navercorp.lucy.security.xss.servletfilter.defender.XssFilterDefender</class>
           <init-param>
               <param-value>lucy-xss.xml</param-value>    <!-- lucy-xss-filter의 dom용 설정파일 -->
               <param-value>false</param-value>         <!-- 필터링된 코멘트를 남길지 여부, 성능 효율상 false 추천 -->
           </init-param>
       </defender>
   </defenders>

    <!-- default defender 선언, 별다른 defender 선언이 없으면 default defender를 사용해 필터링 한다. -->
    <default>
        <defender>xssPreventerDefender</defender>
    </default>

    <!-- global 필터링 룰 선언 -->
    <global>
        <!-- 모든 url에서 들어오는 globalParameter 파라메터는 필터링 되지 않으며 
                또한 globalPrefixParameter로 시작하는 파라메터도 필터링 되지 않는다. -->
        <params>
            <param name="globalParameter" useDefender="false" />
            <param name="globalPrefixParameter" usePrefix="true" useDefender="false" />
        </params>
    </global>

    <!-- url 별 필터링 룰 선언 -->
    <url-rule-set>
       
       <!-- url disable이 true이면 지정한 url 내의 모든 파라메터는 필터링 되지 않는다. -->
       <url-rule>
           <url disable="true">/disableUrl1.do</url>
       </url-rule>
       
        <!-- url1 내의 url1Parameter는 필터링 되지 않으며 또한 url1PrefixParameter로 시작하는 파라메터도 필터링 되지 않는다. -->
        <url-rule>
            <url>/url1.do</url>
            <params>
                <param name="url1Parameter" useDefender="false" />
                <param name="url1PrefixParameter" usePrefix="true" useDefender="false" />
            </params>
        </url-rule>
        
        <!-- url2 내의 url2Parameter1만 필터링 되지 않으며 url2Parameter2는 xssSaxFilterDefender를 사용해 필터링 한다.  -->
        <url-rule>
            <url>/url2.do</url>
            <params>
                <param name="url2Parameter1" useDefender="false" />
                <param name="url2Parameter2">
                    <defender>xssSaxFilterDefender</defender>
                </param>
            </params>
        </url-rule>
    </url-rule-set>
</config>

XssPreventerDefender

  • 문자열에서 HTML으로 인식될만한 요소를 완전히 제거(escape)한다.
  • 이때 escape 할때 apache-common-lang의 StringEscapeUtils 을 내부적으로 사용하고 있다.

[StringEscapeUtils.*escapeHtml4 ]

  • default defender로 설정되는 defender이다.

XssSaxFilterDefender(SAX방식)

  • 화이트리스트 방식으로 설정파일을 작성하여 커스텀하여 필터링 할 수 있다.
 <defender>
     <name>xssSaxFilterDefender</name>
     <class>com.navercorp.lucy.security.xss.servletfilter.defender.XssSaxFilterDefender</class>
     <init-param>
         <param-value>lucy-xss-sax.xml</param-value>   <!-- lucy-xss-filter의 sax용 설정파일 -->
         <param-value>false</param-value>        <!-- 필터링된 코멘트를 남길지 여부, 성능 효율상 false 추천 -->
     </init-param>
 </defender>
  • <init-param> 에서 첫번째 <param-value> 는 사용할 설정파일을 지정한다.
  • 두번째 <param-value> 는 필터링한 코멘트 <!-- Not Allowed Tag Filtered --> 를 남길지 여부, true 로 할 경우 남기지 않는다.

XssFilterDefender(DOM방식)

 <defender>
     <name>xssFilterDefender</name>
     <class>com.navercorp.lucy.security.xss.servletfilter.defender.XssFilterDefender</class>
     <init-param>
         <param-value>lucy-xss.xml</param-value>    <!-- lucy-xss-filter의 dom용 설정파일 -->
         <param-value>false</param-value>         <!-- 필터링된 코멘트를 남길지 여부, 성능 효율상 false 추천 -->
     </init-param>
 </defender>
  • XSsSaxFilterXssFilter 는 xml 을 읽는 방식에 따른 차이만 있음.
    dom용 설정파일에서 추가 옵션이 더 있긴한데, 저는 XssSaxFilter를 사용하였기에 이를 중점적으로 설명)

Default Defender

  • 적용할 XSS Filter를 지정한다.
  • default defender는 XssPreventerDefender로 별도의 설정을 커스텀해서 사용할 경우, XssSaxFilterDefender 혹은 XssFilterDefender를 지정해준다.
<default>
    <defender>xssPreventerDefender</defender>
</default>

Global 필터링 룰

  • 모든 url에서 globalParameter를 지정해서 해당 파라미터는 필터링 되지 않도록 설정할 수 있다.
  • 또한 globalPreFixParameter로 시작하는 파라미터도 필터링에서 제외 할 수 있다.
  • 필터링에서 제외하기 위해선 useDefender=”false”로 지정해줘야 한다.
<global>
    <!-- 모든 url에서 들어오는 globalParameter 파라메터는 필터링 되지 않으며 
            또한 globalPrefixParameter로 시작하는 파라메터도 필터링 되지 않는다. -->
    <params>
        <param name="globalParameter" useDefender="false" />
        <param name="globalPrefixParameter" usePrefix="true" useDefender="false" />
    </params>
</global>

url 필터링 룰

  • url 별 필터링 설정을 적용할 수 있다.
  • <url>disable=”true” 면 해당 url 내의 모든 파라미터에는 필터링 되지 않는다.
  • <url>내에 <param> 으로 해당 url의 특정 파라미터 또한 필터링 되지 않도록 설정할 수 있다.
  • 그리고 <param> 내에 <defender> 를 별도로 설정해서 적용할 필터를 지정할 수 있다.
<url-rule-set>
     <!-- url disable이 true이면 지정한 url 내의 모든 파라메터는 필터링 되지 않는다. -->
     <url-rule>
         <url disable="true">/disableUrl1.do</url>
     </url-rule>
     
      <!-- url1 내의 url1Parameter는 필터링 되지 않으며 또한 url1PrefixParameter로 시작하는 파라메터도 필터링 되지 않는다. -->
      <url-rule>
          <url>/url1.do</url>
          <params>
              <param name="url1Parameter" useDefender="false" />
              <param name="url1PrefixParameter" usePrefix="true" useDefender="false" />
          </params>
      </url-rule>
      
      <!-- url2 내의 url2Parameter1만 필터링 되지 않으며 url2Parameter2는 xssSaxFilterDefender를 사용해 필터링 한다.  -->
      <url-rule>
          <url>/url2.do</url>
          <params>
              <param name="url2Parameter1" useDefender="false" />
              <param name="url2Parameter2">
                  <defender>xssSaxFilterDefender</defender>
              </param>
          </params>
      </url-rule>
  </url-rule-set>

4. Default Defender를 XssSaxFilterDefender로 지정하여 필터링 커스텀해보기

  • lucy-xss-servlet-filter-rule.xmlXssSaxFilterDefender 에서 기본값으로 설정된 lucy-xss-sax.xml 설정파일에 대해 먼저 알아보겠다.
  • 설정파일은 resources 아래에 lucy-xss-servlet-filter-rule.xml 와 동일한 위치에 존재해야 한다.
  • 여기서 본인이 커스텀할 필터링 룰을 작성하면 된다.

lucy-xss-sax.xml

<?xml version="1.0" encoding="UTF-8"?>

<config xmlns="http://www.nhncorp.com/lucy-xss"
	extends="lucy-xss-superset-sax.xml">
	<elementRule>
		<element name="applet" disable="true" />
		<element name="base" disable="true" />
		<element name="body" disable="true" />
		<element name="form" disable="true" />
		<element name="html" disable="true" />
		<element name="iframe" disable="true" />
		<element name="meta" disable="true" />
		<element name="script" disable="true" />
		<element name="style" disable="true" />
		<element name="textarea" disable="true" />
		<element name="xml" disable="true" />
		<element name="xmp" disable="true" />
		<element name="td" endTag="false" />
		<element name="embed" disable="false" />
		<element name="object" removeTag="true" />
	</elementRule>

	<attributeRule>
		<attribute name="src">
			<allowedPattern><![CDATA[['"]?\s*http://.*]]></allowedPattern>
		</attribute>
		<attribute name="href">
			<notAllowedPattern><![CDATA[(?i:script)]]></notAllowedPattern>
			<notAllowedPattern><![CDATA[(?i:\.css)]]></notAllowedPattern>
		</attribute>
		<attribute name="style">
			<notAllowedPattern><![CDATA[(?i:expression)]]></notAllowedPattern>
			<notAllowedPattern><![CDATA[(?i:alert)]]></notAllowedPattern>
		</attribute>
	</attributeRule>
</config>
  • lucy-xss-superset-sax.xml 설정파일을 extends 하고 있다.
  • 설정파일은 화이트리스트 방식으로 작성되었기에 작성한 element는 기본적으로 필터가 적용되지 않는데, disable=”true”를 적용하면 필터링이 적용 된다.
  • disable의 기본값은 false기 때문에, element 선언만 해주고 별도로 disable=”true”로 적용해야 필터링 적용이 적용된다.
  • 설정파일 설정의 더욱 자세한 내용은 아래 글에서 상세히 설명해뒀으니 참고하면 된다. lucy-xss-filter를 사용하여 XSS 공격 방어하기 - 1

lucy-xss-superset-sax.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- version 20180725-1 -->
<config xmlns="http://www.nhncorp.com/lucy-xss" extends="lucy-xss-default-sax.xml">
	<elementRule>
		<element name="body" disable="true" /> <!-- <BODY ONLOAD=alert("XSS")>, <BODY BACKGROUND="javascript:alert('XSS')"> -->
		<element name="embed" disable="true" />
		<element name="iframe" disable="true" /> <!-- <IFRAME SRC=”http://hacker-site.com/xss.html”> -->
		<element name="meta" disable="true" />
		<element name="object" disable="true" />
		<element name="script" disable="true" /> <!-- <SCRIPT> alert(“XSS”); </SCRIPT> -->
		<element name="style" disable="true" />
		<element name="link" disable="true" />
		<element name="base" disable="true" />
	</elementRule>
	<attributeRule>
		<attribute name="data" base64Decoding="true">
			<notAllowedPattern><![CDATA[(?i:s\\*c\\*r\\*i\\*p\\*t\\*:)]]></notAllowedPattern>
			<notAllowedPattern><![CDATA[(?i:d\\*a\\*t\\*a\\*:)]]></notAllowedPattern>
			<notAllowedPattern><![CDATA[&[#\\%x]+[\da-fA-F][\da-fA-F]+]]></notAllowedPattern>
		</attribute>
		<attribute name="src" base64Decoding="true">
			<notAllowedPattern><![CDATA[(?i:s\\*c\\*r\\*i\\*p\\*t\\*:)]]></notAllowedPattern>
			<notAllowedPattern><![CDATA[(?i:d\\*a\\*t\\*a\\*:)]]></notAllowedPattern>
			<notAllowedPattern><![CDATA[&[#\\%x]+[\da-fA-F][\da-fA-F]+]]></notAllowedPattern>
		</attribute>
		<attribute name="style">
			<notAllowedPattern><![CDATA[(?i:j\\*a\\*v\\*a\\*s\\*c\\*r\\*i\\*p\\*t\\*:)]]></notAllowedPattern>
			<notAllowedPattern><![CDATA[(?i:e\\*x\\*p\\*r\\*e\\*s\\*s\\*i\\*o\\*n)]]></notAllowedPattern>
			<notAllowedPattern><![CDATA[&[#\\%x]+[\da-fA-F][\da-fA-F]+]]></notAllowedPattern>
		</attribute>
		<attribute name="href">
			<notAllowedPattern><![CDATA[(?i:j\\*a\\*v\\*a\\*s\\*c\\*r\\*i\\*p\\*t\\*:)]]></notAllowedPattern>
			<notAllowedPattern><![CDATA[&[#\\%x]+[\da-fA-F][\da-fA-F]+]]></notAllowedPattern>
		</attribute>
		<attribute name="formaction" disable="true"/>
	</attributeRule>
</config>
  • lucy-xss-default-sax.xml 설정파일을 extends 하고 있다.

lucy-xss-default-sax.xml

  • HTML 4.0을 기본으로 하며, HTML 5.0과 Internet Explorer에 특화된 몇 가지 명세를 추가한 기본 설정 파일이다.
  • 해당 xml은 내용이 많아서 위에 설정해놓은 링크로 들어가서 확인하길 바란다.

결론

lucy-xss-servlet-filter는 기본적으로 모든 요청 파라미터에 적용되기에, lucy-xss-filter에 비해 설정(lucy-xss-servlet-filter-rule.xml)을 통해서 별로도 filter 적용을 컨트롤 해줘야 한다.

그렇지만 servlet filter에 xss 공격 방어를 적용하였기에 lucy-xss-filter 에 비해 보다 완벽하게 방어할 수 있다.

저는 default Defender로는 XssPreventerDefender를 그대로 사용하고 url 필터링 룰에서, 특정 url에 에디터로 작성한 데이터의 파라미터에는 XssSaxFilterDefender를 적용시켜, 에디터로 적용된 HTML 태그는 그대로 두되, script와 같은 별도의 태그는 removeTag 설정을 적용하였다.

다음 글에선 summernote란 에디터를 사용했을 경우, XssFilter 적용하는데 겪었던 문제를 작성해보겠다.

[참고]

https://github.com/naver/lucy-xss-filter

1개의 댓글

comment-user-thumbnail
2024년 1월 23일

좋은 글 감사합니다. 궁금한 점이 있어 글 남겨봐요. 제가 저 오픈소스를 확인 해본 바로는 xssSaxFilterDefender 나 xssFilterDefender 에서는 html의 tag 완성형으로 주입된 문구에 대해서만 필터링을 수행하던데 이게 맞는 거겠죠? 몇 번이나 확인했지만 혹시나 제가 모르는 부분이 있을까 해서 질문을 남겨봅니다. ^^
솔직히 필터링 정책 xml 파일에 보면 태그 별로, 속성 별로 필터링을 할지 말지 지정하는 부분이 있지만 결국 그 부분을 지정한다는 것은 그 태그랑 속성을 이용한 완성형 태그그 자체로 공격문구 주입이 될 때 탐지 여부를 가리겠단 것 같더군요. 예를 들면 태그 속성 중에서 "script"를 잡겠다고 하면 형식으로 정확하게 주입(완성형 태그 구문)을 시켜야만 필터가 감지하고 필터링 하던데 말이죠. 그럼 반대로 주입되는 부분이 굳이 저렇게 완성형 태그 형식이 아닌 경우에는 저 두 필터로는 차단하기가 어렵다는 게 될텐데 말이죠. 저 둘은 보통 에디터에서 유입되는 html tag 형식의 값을 필터링할 때 필요하다 볼 수 있을 듯 하고 그 외 입력 부분은 무조건 완성형 태그 형식의 공격이 아닌 경우도 많을테니 그냥 XssPreventDefender를 이용해야만 막을 수 있다고 봅니다만 혹시 제가 잘못 알고 있는 부분이 있을까 해서 먼저 경험하신 글쓴이님의 견해를 여쭤보고 싶습니다. ^^

답글 달기