lucy-xss-filter는 크게 두 가지가 존재한다.
1. lucy-xss-filter
2. lucy-xss-servlet-filter
이름에서도 어렴풋이 알 수 있듯이 두번째는 serlvet filter에 추가하는 것이고, 첫번째는 원하는 곳에서 등록한 filter를 불러와서 사용할 수 있다. serlvet filter를 사용하게 될 경우, 모든 요청 파라미터를 검사하기에 신중히 사용해야 한다.
해당 글에선 lucy-xss-filter에 대해서만 알아본다.
<dependency>
<groupId>com.navercorp.lucy</groupId>
<artifactId>lucy-xss</artifactId>
<version>X.X.X</version>
</dependency>
StringEscapeUtils
을 내부적으로 사용하고 있다.[StringEscapeUtils.escapeHtml4
]
XssPreventer.escape(String)
메서드를 호출하여 사용하면 된다.// escape
String clean = XssPreventer.escape(dirty);
// unescape
String dirty = XssPreventer.unescape(clean);
<config xmlns="http://www.nhncorp.com/lucy-xss" extends="...">
<elementRule>
</elementRule>
<attributeRule>
</attributeRule>
<elementGroup name="...">
</elementGroup>
<attributeGroup name="...">
</attributeGroup>
</config>
'config’는 최상위 요소(root element)로서 다음과 같은 속성과 내용을 포함한다.
xmlns
: 디폴트 네임스페이스extends
: 상속 받을 설정 파일 이름(해당 파일 내에 정의된 “config”를 모두 상속받는다.)elementRule
: 적용 가능한 모든 요소에 대한 필터링 규칙을 설정한다.attributeRule
: 적용 가능한 모든 속성에 대한 필터링 규칙을 설정한다.elementGroup
: 요소의 집합을 정의한다. (DOM 방식에서만 사용)attributeGroup
: 속성의 집합을 정의한다. (DOM 방식에서만 사용)filteringTagInComment
: HTML 주석(<!-- 주석 -→) 내에 존재하는 요소(HTML 태그)에 대한 필터링 여부와 타입을 설정한다.<elementRule>
<element name="a" endTag="true" override="true" disable="false">
<attributes>
<ref name="Common" />
</attributes>
<listener>com.nhncorp.security.xss.XXXListener</listener>
</element>
</elementRule>
elementRule
: 하나 이상의 element 요소로 정의되며, element 필터링 규칙에 없는 요소는 필터링 대상이 된다.element
: 하나의 요소에 대한 필터링 규칙을 설정한다.name
: 요소 이름endTag
: End Tag의 존재 유무를 true/false
로 설정한다. 디폴트는 false
이다. (DOM 방식에서만 사용)override
: 'extends' 속성에 기술한 상위 설정 파일에 동일한 설정이 있으면 그 설정을 상속받을지를 설정한다. 디폴트는 true
이다.disable
: name
에 설정된 요소를 elementRule
에서 제거할지 설정한다. 디폴트는 false
이다.removeTag
: 필터링 결과물에서 element의 삭제 유무를 true/false
로 설정한다. 디폴트는 false
이다. 가령 의 내용만 사용되는 경우, , , 등을 삭제하는데 사용될 수 있다.listener
: 이 화이트리스트 설정 파일의 설정만으로 해당 요소를 필터링할 수 없는 경우, com.nhncorp.lucy.security.xss.event.ElementListener
인터페이스를 상속하여 구현한 클래스 이름을 입력한다.// 파라미터는 적용할 설정파일 명을 입력하면 된다.
// 설정파일의 종류는 아래에서 더 자세히 설명하겠다.
XssFilter filter = XssFilter.getInstance("lucy-xss-superset.xml");
@Test
public void testDirtyCodeFiltering() throws Exception {
String dirty = "<script></script>";
String clean = filter.doFilter(dirty);
String expected = "<script></script>"; // 예상 문자열
assertEquals(expecte, clean);
}
⇒ 설정파일을 크게 두가지 종류가 존재하는데, 이는 XML parse 방식에 따라 나뉜다.
SAX 방식은 라인을 하나하나 읽어 순차적으로 파싱하는데 반해,
DOM 방식은 메모리에 모두 로드한 후 파싱한다.
⇒ XssSaxFilter는 DOM 트리 생성 과정 및 부모 자식 간의 검사가 생략되어 DOM 방식에 비해 속도가 약 20% 빨라졌다. 특히 중첩된 태그가 많은 인풋일 수록 SAX 방식에서 큰 속도 향상이 있다.
XssSaxFilter.getInstance()
메서드로 설정 파일을 지정하지 않은 경우에는 lucy-xss-superset-sax.xml
파일을 클래스패스에서 찾아 읽는다. lucy-xss-superset-sax.xml
파일이 존재하지 않으면, jar 파일에 내장된 lucy-xss-default-sax.xml
을 읽어 들인다.lucy-xss-sax.xml
파일을 생성하여, extends 파일을 lucy-xss-superset-sax.xml
지정한다. 그 후 설정을 추가해준다.// 설정파일 지정 x
XssSaxFilter filter = XssSaxFilter.getInstance();
// 추가적인 설정을 해야할 경우
// 1. lucy-xss-sax.xml 생성 후, extends 파일을 lucy-xss-superset-sax.xml 지정
<config xmlns="http://www.nhncorp.com/lucy-xss" extends="lucy-xss-superset-sax.xml">
<elementRule>
</elementRule>
<attributeRule>
</attributeRule>
</config>
// 2. lucy-xss-sax.xml을 설정파일로 지정
XssSaxFilter otherFilter = XssSaxFilter.getInstance("lucy-xss-sax.xml");
// 두번째 파라미터는 공격패턴 검출시 디버그를 위해 추가되는 주석문을 표시하지 않는 여부이다.
// 기본값(false)는 주석을 남기는데, true 로 별도 지정시 주석을 남기지 않는다.
// 주석문 <!-- Not Allowed Attribute Filtered (태그명) -->
XssSaxFilter otherFilterNoComment = XssSaxFilter.getInstance("lucy-xss-sax.xml", true);
</div>
, 필터링 후: </div>
</div>
만 있을 경우 필터링 처리되어 </div>
가 출력된다.⇒ Lucy-XSS Filter 객체를 생성하면 Configuration Builder는 White List Configuration에 정의된 내용을 바탕으로 White List Object Model을 생성하여 Lucy-XSS Filter Core로 전달한다. Lucy-XSS Filter Core는 Markup Parser(DOM, SAX 둘 다 지원 )가 필터링 대상 HTML 문자열을 파싱하여 생성한 HTML Object Model을 White List Object Model과 비교하여 필터링한다.
lucy-xss-filter는 개발자가 적용해야 할 곳에 직접 작성해 줘야 하기 때문에, 결국은 보다 완벽하게 XSS 공격 방어를 할 수 없다. 그래서 servlet filter에 lucy-xss-servlet-filter를 적용하여 요청 파라미터 모두를 검사하도록 하기로 하였다. 그래서 실제로 커스텀해서 적용하는 부분은 다음 작성할 글에서 더욱 자세히 확인가능하다.
[참고]