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

sarah·2022년 12월 16일
1

xss

목록 보기
1/3
💡 스프링으로 프로젝트를 진행하다 게시판에서 에디터를 사용하면서 디비에 html 태그를 저장하게 되었다. 그 과정에서 XSS 공격을 방지하는 필터를 적용하기 위해 방법을 찾다가, 네이버가 제공하는 XSS 공격을 방어하는 라이브러리 ‘lucy-xss-filter’를 사용하기로 하였다.

lucy-xss-filter는 크게 두 가지가 존재한다.
1. lucy-xss-filter
2. lucy-xss-servlet-filter
이름에서도 어렴풋이 알 수 있듯이 두번째는 serlvet filter에 추가하는 것이고, 첫번째는 원하는 곳에서 등록한 filter를 불러와서 사용할 수 있다. serlvet filter를 사용하게 될 경우, 모든 요청 파라미터를 검사하기에 신중히 사용해야 한다.
해당 글에선 lucy-xss-filter에 대해서만 알아본다.

lucy-xss-filter

  • pom.xml에 아래의 의존성을 추가한다.
<dependency>
    <groupId>com.navercorp.lucy</groupId>
    <artifactId>lucy-xss</artifactId>
    <version>X.X.X</version>
</dependency>
  • lucy-xss-filter는 크게 두 가지 필터가 존재한다.
    => XssPreventer & XssFilter

1. XssPreventer

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

[StringEscapeUtils.escapeHtml4 ]

  • 특별한 설정없이 XssPreventer.escape(String) 메서드를 호출하여 사용하면 된다.
// escape
String clean = XssPreventer.escape(dirty);

// unescape
String dirty = XssPreventer.unescape(clean);

2. XssFilter

  • XSS 공격이 가능한 HTML 요소를 신뢰할 수 있는 코드로 변환하거나 삭제하는 기능을 제공한다. 공격이 가능하지 않은 HTML 요소는 허용을 한다.
  • 선택적으로 적용하기 위해선 설정파일을 설정해야 한다.
  • 설정파일을 작성할때는 화이트리스트 방식으로 작성한다.
    (화이트리스트 방식 ⇒ 허용되는 내용을 제외한 모든 부분을 필터링하여 새로운 공격 유형에 대해서도 대처 가능)
  • 화이트리스트 설정 파일은 XML 형식으로 작성하며 상위 설정 파일을 상속하거나 오버라이딩 할 수 있다.

2-1. 설정파일

  • 화이트리스트 방식의 설정파일은 아래의 구조와 같다.
<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 태그)에 대한 필터링 여부와 타입을 설정한다.

2-2. elementRule

  • 적용 가능한 모든 요소에 대한 필터링 규칙을 정의하며 다음과 같이 작성한다.
<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 이다.
      (true로 할 경우 필터링 대상이 된다. false 혹은 생략할 경우 필터링 대상에서 제외된다.)
    • removeTag : 필터링 결과물에서 element의 삭제 유무를 true/false 로 설정한다. 디폴트는 false 이다. 가령 의 내용만 사용되는 경우, , , 등을 삭제하는데 사용될 수 있다.
  • listener : 이 화이트리스트 설정 파일의 설정만으로 해당 요소를 필터링할 수 없는 경우, com.nhncorp.lucy.security.xss.event.ElementListener 인터페이스를 상속하여 구현한 클래스 이름을 입력한다.

3. 사용법

  • XssFilter를 사용하기 위해선 아래와 같은 방법으로 사용가능하다.
// 파라미터는 적용할 설정파일 명을 입력하면 된다.
// 설정파일의 종류는 아래에서 더 자세히 설명하겠다.
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 = "&lt;script&gt;&lt;/script&gt;"; // 예상 문자열
    assertEquals(expecte, clean);
}

⇒ 설정파일을 크게 두가지 종류가 존재하는데, 이는 XML parse 방식에 따라 나뉜다.
SAX 방식라인을 하나하나 읽어 순차적으로 파싱하는데 반해,
DOM 방식메모리에 모두 로드한 후 파싱한다.

XssSaxFilter는 DOM 트리 생성 과정 및 부모 자식 간의 검사가 생략되어 DOM 방식에 비해 속도가 약 20% 빨라졌다. 특히 중첩된 태그가 많은 인풋일 수록 SAX 방식에서 큰 속도 향상이 있다.

4. XssSaxFilter(SAX방식)

  • 기본적으로 제공되는 SAX 방식용 화이트리스트 설정 파일은 다음과 같다.
  • lucy-xss-default-sax.xml
    • HTML 4.0을 기본으로 하며, HTML 5.0과 Internet Explorer에 특화된 몇 가지 명세를 추가한 기본 설정 파일이다.
    • lucy-xss-x.x.x.jar 파일 내부에 포함되어 배포된다.
  • lucy-xss-superset-sax.xml
    • lucy-xss-default-sax.xml을 상속받아 작성된 파일이다. 회사의 보안부서에서 기초 정책을 정의하고 있다.
    • 이 저장소의 conf 디렉토리 아래에서 배포된다.
  • 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 지정한다. 그 후 설정을 추가해준다.
    (lucy-xss-sax.xml 파일 예시 ⇒ https://github.com/naver/lucy-xss-filter/blob/master/conf/lucy-xss-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);
  • XssSaxFilter는 아래와 같은 규칙으로 필터링을 한다.
    • 닫는 태그를 검사하지 않는다(닫는 태그가 없다고 공격 태그로 간주하지는 않는다).
    • 부모 자식 관계는 검사하지 않는다(ex) DIV 태그가 어느 태그에도 올 수 있다).
    • 태그와 속성 관계 또한 검사하지 않는다(속성의 사용가능 여부, 속성 값의 XSS 공격 검사는 여전히 한다).
    • start tag 없이 end tag만 있을 경우, 필터링 없이 그대로 노출한다.
      • 예) 필터링 전: </div>, 필터링 후: </div>
    • 기존 XssFilter는 </div> 만 있을 경우 필터링 처리되어 &lt;/div&gt; 가 출력된다.
    • 태그, 속성들의 포함관계를 검사하지 않기 때문에, 서비스 입장에서는 특정 위치에서의 태그 사용을 위해 필요했던 추가적인 설정들이 줄어든다.

5. XssFilter (DOM 방식)

  • DOM 방식의 XssFilter를 위해 기본 제공되는 화이트리스트 설정 파일은 아래와 같다.
  • lucy-xss-default.xml
    • HTML 4.0을 기본으로 하며, HTML 5.0과 Internet Explorer에 특화된 몇 가지 명세를 추가한 기본 설정 파일이다.
    • lucy-xss-x.x.x.jar 파일 내부에 포함되어 배포된다.
  • lucy-xss-superset.xml
    • lucy-xss-default.xml을 상속받아 작성된 파일이다. 회사의 보안부서에서 기초 정책을 저으이하고 있다.
    • 이 저장소의 conf 디렉토리 아래에서 배포된다.

6. 내부구조

  • Lucy-XSS Filter는 다음과 같은 요소로 구성된다

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 Core : Markup Parser를 통해 파싱한 HTML 문자열을 White List Object Model과 비교하여 필터링한 결과(Clean HTML)를 반환한다.
  • Markup Parser : 문자열을 파싱하여 HTML Object Model로 변환한다. DOM(MarkupParser.java)과 SAX(MarkupSaxParser.java) 두 가지 방식이 존재한다.
  • Configuration Builder : White List Configuration에 정의된 내용을 바탕으로 White List Object Model을 생성한다.
  • White List Configuration : 정상적인 HTML 구조를 화이트리스트 방식으로 정의한 설정 파일로서, XML 형식으로 되어 있다.

결론

lucy-xss-filter는 개발자가 적용해야 할 곳에 직접 작성해 줘야 하기 때문에, 결국은 보다 완벽하게 XSS 공격 방어를 할 수 없다. 그래서 servlet filter에 lucy-xss-servlet-filter를 적용하여 요청 파라미터 모두를 검사하도록 하기로 하였다. 그래서 실제로 커스텀해서 적용하는 부분은 다음 작성할 글에서 더욱 자세히 확인가능하다.

[참고]

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

0개의 댓글