크로스 사이트 스크립팅은 매우 위험한 보안 노출로서 안전한 웹 기반 애플리케이션을 설계할 때 반드시 고려해야 한다. 이 글에서 노출의 본질과, 이것이 어떻게 영향을 미치는지를 설명하고 솔루션 전략을 소개한다. 오늘날 대부분의 웹 사이트는 동적 컨텐트를 웹 페이지에 추가하여 사용자에게 더 많은 즐거움을 선사한다. 동적 컨텐트는 몇몇 서버 프로세스에서 만들어진 컨텐트로서, 설정과 필요에 따라 다르게 작동하고 디스플레이 된다. 동적 웹 사이트는 정적 웹 사이트에는 없는 위험성도 지니고 있다. 이를 "크로스 사이트 스크립팅(cross-site scripting) "이라고 한다. 일명 "XSS"라고도 알려져 있다.
"웹 페이지는 텍스트와 HTML 마크업으로 구성된다. 이들은 서버에 의해 만들어지고 클라이언트 브라우저에 의해 인터프리팅 된다. 정적 페이지만을 만들어 내는 웹 사이트는 브라우저 사용자가 이러한 페이지들을 인터프리팅하는 방식을 완전히 제어할 수 있다. 동적 페이지를 만들어 내는 웹 사이트는 클라이언트가 아웃풋을 인터프리팅 하는 방식을 완전히 제어하지는 못한다. 신뢰할 수 없는 컨텐트가 동적 웹 페이지에 들어갈 수 있다는 것이 문제의 본질이다. 웹 사이트나 클라이언트도 이러한 현상을 인식하여 방어할 수 있는 충분한 정보가 없다." 인터넷 보안 취약성을 연구하는 CERT Coordination Center의 설명이다.
크로스 사이트 스크립팅은 공격자들에게는 이미 유명해졌다. 매월 크로스 사이트 스크립팅 공격이 상용 사이트에서 발생하고 그러한 위험성을 설명하는 경고문이 발표된다. 주의하지 않는다면 여러분의 웹 사이트나 회사도 이러한 공격의 희생양이 될 것이다.
이 글에서 이러한 위협에 대한 경각심을 일깨우고 웹 애플리케이션에 보안을 구현하여 공격을 피하는 방법을 설명하고자 한다.
크로스-사이트 스크립팅의 쓰레드
크로스 사이트 스크립팅으로 인해 다음과 같은 위험에 빠지게 된다.
공격자에 의해 제공된 컨텐트에 기반하여 동적으로 생성된 페이지들을 볼 때 사용자들은 자신도 모르게 악의적인 스크립트를 실행할 수 있다. 공격자는 사용자 세션 쿠키가 종료되기 전에 사용자 세션을 인계 받을 수 있다. 침입자는 사용자를 악의적인 서버로 연결할 수 있다. 공격자가 제공한 URL로 사용자가 접근할 수 있도록 할 수 있는 침입자는 공격자가 선택한 스크립트나 HTML이 사용자 브라우저에서 실행될 수 있도록 할 수 있다. 이러한 기술을 사용하여 공격자는 URL로 접근했던 사용자의 권한을 사용하여 액션을 취할 수 있다. SQL 데이터베이스에 쿼리를 실행하거나 결과를 보고 목표 시스템 구현의 오류를 악용할 수 있다.
위로
공격 시작하기
웹 사이트상의 애플리케이션이 크로스 사이트 스크립팅에 취약하다고 알려지면 공격자는 공격을 구상하게 된다. 공격자가 가장 빈번하게 사용하는 기술은 공격 목표의 시스템에 공격 목표의 권한을 사용하여 실행할 수 있도록 xxJavaScript, VBScript, ActiveX, HTML, Flash를 투입하는 것이다. 공격이 활성화 되면 계정 하이재킹, 사용자 설정 변경, 쿠키 훔치기 및 오염, 오류 광고 등이 가능하다.
위로
공격 시나리오 샘플
다음 시나리오 다이어그램은 비교적 빈번하게 발생하는 공격 유형이다. 다양한 취약성 유형들까지 다 설명할 수는 없다. 자세한 내용은 아래 참고자료 섹션을 참조하기 바란다.
악의적인 링크를 통한 스크립팅
이 시나리오에서 공격자는 특별하게 고안한 이메일 메시지를 공격 목표로 보낸다. 여기에는 아래와 같은 악의적인 링크 스크립팅이 포함되어 있다.
malicious code>Click here 아무것도 모르는 사용자가 이 링크를 클릭하면 URL은 악의적인 코드를 담고 있는 legitimateSite.com으로 간다. 합법적인 서버가 clientprofile의 값을 포함하는 사용자에게 페이지를 보내면 악의적인 코드가 클라이언트 웹 브라우저에서 실행된다.(그림 1)
그림 1. 이메일을 통한 공격
사용자의 쿠키 훔치기
웹 사이트의 일부가 쿠키를 사용한다면 사용자에게서 쿠키를 훔칠 수도 있다. 이 시나리오에서, 공격자는 악의적인 스크립트를 가진 페이지를 취약한 사이트의 일부에 끼워넣는다. 페이지가 디스플레이 되면 악의적인 스크립트가 실행되고 사용자 쿠키를 모으고 요청을 공격자의 웹 사이트로 보낸다. 이 방법을 사용하여 공격자는 패스워드, 신용카드 번호, 사용자 인풋 정보 등의 민감한 데이터를 취할 수 있다.( 그림 2)
그림 2. 쿠키 훔치기와 계정 하이재킹
비권한 요청 보내기
이 시나리오에서 사용자는 메일 메시지의 악의적인 링크를 따라가게 되면 공격자가 작성한 스크립트를 실행한다. 악의적인 스크립트는 합법적인 서버에서 온 것 처럼 보이는 상황 속에서 실행되기 때문에 공격자는 문서에 접근할 수 있으며 페이지에 포함된 데이터를 사이트로 보낼 수 있다. 삽입된 스크립트 코드가 희생자를 바꾸지 않고도 합법적인 서버와 인터랙팅 할 수 있다면 공격자는 그 데이터를 개발 및 악용하여 합법적인 웹 서버 상의 또 다른 페이지에 활용할 수 있다.(그림 3)
그림 3. 비권한 요청 보내기
위로
공격 피하기
앞서 언급했던 것 처럼, 공격자가 합법적인 웹 서버가 공격자가 선택한 악의적인 스크립트를 포함하고 있는 대상 사용자의 웹 브라우저로 페이지를 보냄으로서 크로스 사이트 스크립팅이 실현된다. 공격자는 합법적인 웹 서버에서 온 합법적인 스크립트 권한을 갖고 악의적인 스크립트를 실행한다.
지금까지 공격의 기초에 대해 알아보았다. 이제는 방어할 차례이다.
웹 사이트 개발자는 동적으로 생성된 페이지들에 원치 않던 태그가 포함되지 않도록 함으로서 공격을 피할 수 있다.
웹 사용자의 관점에서 볼 때 공격 위험성을 줄이는 두 가지 옵션이 있다. 첫 번째는 웹 브라우저 뿐만 아니라 HTML 이메일 클라이언트에서 스크립팅 언어가 실행되지 못하게 하는 것이다. 이는 강력한 보호막이 되지만 기능까지 수행하지 못하게 한다는 점이 부작용이다. 두 번째는 메인 웹 사이트에서 온 링크만 따라가는 것이다. 이는 사용자 노출을 최대한 줄이면서 기능은 유지된다.
하지만, 웹 사용자가 선택할 수 있는 솔루션 중 어떤 것도 완벽한 것은 없다. 결국 페이지를 수정하여 문제를 줄이는 웹 페이지 개발자의 손에 달려있다. 인풋을 적절히 필터링 및 확인하고 사용자에게 갈 아웃풋을 암호화 및 필터링 해야 한다.
필터링
이러한 접근 방식의 기초는 사용자 인풋을 절대 신뢰하지 말고 HTML 스팩에서 정의된 메타문자("특수" 문자)를 언제나 필터링 하는 것이다. 링크 매개변수를 포함하여 각 인풋 필드는 스크립트 태그에 대해 밸리데이션 될 것이다. 악의성이 발견되면 인풋은 거절되고 악의적인 HTML이 사용자에게 제공되는 것을 막을 수 있다.
게다가 많은 웹 브라우저가 HTML에서 일반적인 에러를 수정하려 들기 때문에 복잡해 진다. 결과적으로 그 스팩에 의해 문자를 특수 문자로 취급한다. 전혀 그렇지 않은데 말이다. 따라서 특수한 상황이 있다는 것도 인정해야 한다 웹 개발자들은 애플리케이션을 검사하고 어떤 문자들이 자신의 웹 애플리케이션에 영향을 미치는지를 결정해야 한다.
인풋쪽에서 필터링 하는 것은 덜 효과적이다. 동적 컨텐트는 HTTP외 다른 방식을 통해 웹 사이트 데이터베이스로 들어갈 수 있기 때문이다. 이 경우, 웹 서버는 데이터 인풋 프로세스의 일부가 되는 데이터를 결코 볼 수 없고 데이터 엘리먼트는 여전히 오염된 상태로 남아있다. 가끔은 데이터 아웃풋 프로세스의 일부로 필터링을 수행하는 것이 좋다. 동적 페이지의 일부로 렌더링 되기 바로 직전에 말이다. 정확히만 수행된다면 이러한 접근 방식을 통해 모든 동적 컨텐트가 필터링 될 수 있다.
암호화
웹 서버가 모아진 페이지들이 적절히 암호화 되어 의도하지 않던 스크립트의 실행을 방지할 때 크로스 사이트 스크립팅 공격을 피할 수 있다.
ISO-8859-1 스팩의 각 문자는 숫자 엔트리 값을 사용하여 암호화 될 수 있다. 서버측 암호화란 스크립팅 태그들이 선택된 문자 세트의 코드로 대체되는 곳에서 모든 동적 컨텐트가 암호화 기능을 수행하는 프로세스이다.
여러분은 어떤 문자가 합법적으로 입력되고 통과할 수 있는지를 결정할 수 없기 때문에 암호화가 필요하다. 안타깝게도, 신뢰할 수 없는 모든 데이터를 암호화 하면 리소스 중심이 될 수 있고 몇몇 웹 서버의 퍼포먼스에 영향을 미칠 수 있다.
위로
나에게 맞는 전략
브라우저에서 필드 편집 체크를 하는 CGI 기반 웹 애플리케이션이나 기타 애플리케이션들은 기존 필드 편집 체크를 확장하여 크로스 사이트 스크립팅 취약성까지 아우르는 필터링 전략에 알맞다. 브라우저 측 필드 편집 체크가 서버로 가는 몇 가지 실행을 줄여주기는 하지만, 정직한 사용자에게만 해당하고 모든 인풋 필드가 체크되었다는 것을 보장하기 위해서는 코드 전체를 검사해야 한다. 서버측 밸리데이션으로 설계된 웹 애플리케이션은 두 전략 중 하나 또는 모두에 적용될 수 있다.
필터링 전략이 효과를 거두기 위해서는 웹 개발자들은 필터링용 메타문자 리스트가 최신 애플리케이션의 필요에 맞는 것인지를 확인해야 한다. 반면, 암호화 전략은 기존 애플리케이션 코드와 애플리케이션 기능에 영향을 덜 미친다. 이 같은 이유 때문에 암호화 전략이 구현 시 많이 선택된다. 암호화 구현 샘플은 다음에 설명하겠다.
위로
샘플 암호화의 기초
웹 서버가 생성된 페이지들이 알맞게 암호화 되었다는 것을 확인할 수 있는 간단하지만 효과적인 방법은 암호화 기능을 통해 동적 컨텐트의 각 문자로 전달하는 것이다. 이때 동적 컨텐트의 스크립팅 태그는 선택된 문자 세트의 코드로 대체된다. 이 작업은 커스텀 태그 라이브러리에 가장 적합하다.
커스텀 태그 라이브러리 기초
커스텀 태그 라이브러리는 한 개 이상의 자바 클래스(태그 핸들러)와 XML 태그 라이브러리 디스크립션 파일(TLD)로 구성된다. 이것은 새로운 태그 이름과 그러한 태그에 유효한 애트리뷰트를 나타낸다. 태그 핸들러와 TLD는 태그, 애트리뷰트, 바디가 JSP 페이지 내에서 요청 시 어떻게 인터프리팅 되고 처리되는지를 결정한다. 커스텀 태그 라이브러리는 복잡한 연산을 캡슐화 할 때 자바 빈 보다 유연한 아키텍처를 제공한다.
위로
"사용자" 에 맞춘 태그 라이브러리
XSS라는 이름 외에 우리의 커스텀 태그 라이브러리에 맞는 더 낳은 이름은 없을까? 태그 라이브러리는 서블릿 컨테이너로 플러그인 되는 소프트웨어 컴포넌트이다. 서블릿 컨테이너는 태그 핸들러를 만들고 이를 초기화 하여 doStartTag(), doEndTag(), release() 메소드를 순서대로 호출한다.
이러한 인터랙션을 통해 우리의 XSS 커스텀 태그 라이브러리는 JSP 페이지에서 발견된 동적 데이터를 암호화 하는 "사용자" 액션을 사용할 수 있다. 커스텀 태그를 구현하는 일은 단순하다.
태그를 설명하는 태그 라이브러리 디스크립터(.tld)를 만든다. taglib 명령어를 이 태그를 사용하는 JSP 파일에 추가한다. TagSupport를 확장하고 doStartTag()와 doEndTag() 메소드를 오버라이드 하는 태그 핸들러를 구현한다.
TLD(tag library descriptor)
태그 라이브러리 디스크립터는 엘리먼트가 특정 태그 라이브러리를 기술하는 XML 파일이다. XSS 커스텀 태그 라이브러리용 tld 파일은 Listing 1을 참조하라. 이 태그 엘리먼트는 property 애트리뷰트를 포함하여 encode 액션을 정의한다. tagclass 엘리먼트는 태그 핸들러 클래스 EncodeTag를 정의한다.
태그 핸들러는 JSP 페이지가 실행될 때 액션들을 평가하는 것을 돕는 웹 컨테이너에 있는 객체이다. EncodeTag 클래스는 암호화 액션을 위한 태그 핸들러이다. doStartTag 메소드는 동적 컨텐트를 ISO-8859-1 문자 세트로 암호화 한다. (Listing 2)
Listing 2. 동적 컨텐트의 암호화
public int doStartTag() throws JspException {
StringBuffer sbuf = new StringBuffer();
char[] chars = property.toCharArray(); for (int i = 0; i < chars.length; i++) { sbuf.append("&#" + (int) chars[i]); }
XSS 커스텀 태그 라이브러리는 웹 애플리케이션의 일부이고 다음과 같이 추가 파일로서 웹 애플리케이션의 WAR 파일로 패키징 된다.
WEB-INF/lib/encodetaglib.jar WEB-INF/tlds/xss.tld
위로
작동시키기
다음 시나리오에서는 커스텀 태그 라이브러리가 어떻게 사용되는지를 설명한다. 아티클을 받는 가상의 웹 사이트에 제출된 아티클을 리뷰하는 페이지를 포함시켰다. 동적 컨텐트인 아티클 아이템은 <%= expression %>구문을 사용하여 JSP 파일 안에 준비된다.
공격자가 악의적인 스크립트를 포함하고 있는 페이지를 등록된 회원의 웹 사이트에 넣었다. 이러한 공격의 결과로 사용자 브라우저에서 실행될 때 팝업 창이 뜬다. ( 그림 4)
그림 4. 암호화 전
다음 시나리오에서는 가상의 웹 사이트에서 생성된 페이지들이 XSS 커스텀 태그 라이브러리를 사용하여 올바르게 암호화 되고 공격을 방어한다는 것을 보여준다. 신뢰할 수 없는 데이터는 브라우저에 나타난다. ( 그림 5)
그림 5. 암호화 후
위로
요약
공격자들이 크로스 사이트 스크립팅을 사용하여 웹 사이트를 공격하는 방법을 설명했다. 또한 웹 사이트가 간단한 커스텀 태그 라이브러리를 사용하여 동적 컨텐트를 암호화 하는 것으로도 이러한 공격을 줄일 수 있다는 것을 설명했다. XSS 커스텀 태그 라이브러리를 그대로 사용하거나 이를 변형하여 자신의 웹 애플리케이션에 맞출 수 있다.
위로
참고자료
The CERT Coordination Center
Malicious HTML Tags Embedded in Client Web Requests.
JSP and custom tag libraries from IBM developerWorks.