⇒ 이러한 이유로 lucy-xss-servlet-filter를 적용하면 웹어플리케이션으로 들어오는 모든 요청 파라메터에 대해 기본적으로 XSS 방어 필터링을 수행가능하다.
⇒ 또한 lucy-xss-servlet-filter는 아래와 같은 방법 필터링 설정을 추가할 수 있다.
기존 시스템에 적용하시려면 lucy-xss-filter를 사용해 개발자가 일일히 필터링 하는 방식을 추천드립니다. 하지만 이 방법은 개발자의 집중력를 믿어야 하기 때문에 언젠가는 뚫릴 수 밖에 없는 방식입니다. 그렇기 때문에 시간을 충분히 확보하실 수 있으시거나 기존에 서블릿 필터 기반으로 XSS 공격을 방어하셨다면 이번 기회에 lucy-xss-servlet-filter를 적용해 XSS 공격에서 해방되시는 걸 추천드립니다.
<dependency>
<groupId>com.navercorp.lucy</groupId>
<artifactId>lucy-xss-servlet</artifactId>
<version>2.0.0</version>
</dependency>
<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>
<?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>
StringEscapeUtils
을 내부적으로 사용하고 있다.[StringEscapeUtils.*escapeHtml4
]
<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 로 할 경우 남기지 않는다. <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>
XSsSaxFilter
와 XssFilter
는 xml 을 읽는 방식에 따른 차이만 있음.XssPreventerDefender
로 별도의 설정을 커스텀해서 사용할 경우, XssSaxFilterDefender
혹은 XssFilterDefender
를 지정해준다.<default>
<defender>xssPreventerDefender</defender>
</default>
useDefender=”false”
로 지정해줘야 한다.<global>
<!-- 모든 url에서 들어오는 globalParameter 파라메터는 필터링 되지 않으며
또한 globalPrefixParameter로 시작하는 파라메터도 필터링 되지 않는다. -->
<params>
<param name="globalParameter" useDefender="false" />
<param name="globalPrefixParameter" usePrefix="true" useDefender="false" />
</params>
</global>
<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>
lucy-xss-servlet-filter-rule.xml
의 XssSaxFilterDefender
에서 기본값으로 설정된 lucy-xss-sax.xml
설정파일에 대해 먼저 알아보겠다.lucy-xss-servlet-filter-rule.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”
로 적용해야 필터링 적용이 적용된다.<?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-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 적용하는데 겪었던 문제를 작성해보겠다.
[참고]
좋은 글 감사합니다. 궁금한 점이 있어 글 남겨봐요. 제가 저 오픈소스를 확인 해본 바로는 xssSaxFilterDefender 나 xssFilterDefender 에서는 html의 tag 완성형으로 주입된 문구에 대해서만 필터링을 수행하던데 이게 맞는 거겠죠? 몇 번이나 확인했지만 혹시나 제가 모르는 부분이 있을까 해서 질문을 남겨봅니다. ^^
솔직히 필터링 정책 xml 파일에 보면 태그 별로, 속성 별로 필터링을 할지 말지 지정하는 부분이 있지만 결국 그 부분을 지정한다는 것은 그 태그랑 속성을 이용한 완성형 태그그 자체로 공격문구 주입이 될 때 탐지 여부를 가리겠단 것 같더군요. 예를 들면 태그 속성 중에서 "script"를 잡겠다고 하면 형식으로 정확하게 주입(완성형 태그 구문)을 시켜야만 필터가 감지하고 필터링 하던데 말이죠. 그럼 반대로 주입되는 부분이 굳이 저렇게 완성형 태그 형식이 아닌 경우에는 저 두 필터로는 차단하기가 어렵다는 게 될텐데 말이죠. 저 둘은 보통 에디터에서 유입되는 html tag 형식의 값을 필터링할 때 필요하다 볼 수 있을 듯 하고 그 외 입력 부분은 무조건 완성형 태그 형식의 공격이 아닌 경우도 많을테니 그냥 XssPreventDefender를 이용해야만 막을 수 있다고 봅니다만 혹시 제가 잘못 알고 있는 부분이 있을까 해서 먼저 경험하신 글쓴이님의 견해를 여쭤보고 싶습니다. ^^