웹 페이지에 악의적인 스크립트를 포함시켜 사용자 측에서 실행되게 유도할 수 있다.
예를 들어, 검증되지 않은 외부 입력이 동적 웹페이지 생성에 사용될 경우, 전송된 동적 웹페이지를 열람하는 접속자의 권한으로 부적절한 스크립트가 수행되어 정보유출 등의 공격을 유발할 수 있다.
외부 입력값 또는 출력값에 스크립트가 삽입되지 못하도록 문자열 치환 함수를 사용
& < > " ' /( )등을 & < > " ' / ( )로 치환하거나,
JSTL 또는 잘알려진 크로스 사이트 스크립트 방지 라이브러리를 활용
HTML 태그를 허용하는 게시판에서는 허용되는 HTML 태그들을 화이트리스트로 만들어 해당 태그만 지원하도록 한다.
Reflected XSS 공격검색 결과, 에러 메시지 등으로 서버가 외부에서 입력받은 악성 스크립트가 포함된 URL 파라미터 값을 사용자 브라우저에서 응답할 때 발생한다.
공격 스크립트가 삽입된 URL을 사용자가 쉽게 확인할 수 없도록 변형하여, 이메일, 메신저, 파일등으로 실행을 유도하는 공격이다.
Stored XSS 공격은 웹 사이트의 게시판, 코멘트 필드, 사용자 프로필 등의 입력 form으로 악성스크립트를 삽입하여 DB에 저장되면, 사용자가 사이트를 방문하여 저장되어 있는 페이지에 정보를 요청할 때, 서버는 악성 스크립트를 사용자에게 전달하여 사용자 브라우저에서 스크립트가 실행되면서 공격한다.
DOM기반 XSS 공격은 외부에서 입력받은 악성 스크립트가 포한된 URL 파라미터 값이 서버를 거치지 않고, DOM 생성의 일부로 실행되면서 공격한다.
Reflected XSS 및 Stored XSS 공격은서버 애플리케이션 취약점으로 인해, 응답 페이지에 악성 스크립트가 포함되어 브라우저로 전달되면서 공격하는 것인 반면, DOM기반 XSS는 서버와 관계없이 발생하는 것이 차이점이다.
<% String keyword = request.getParameter("keyword"); %>
//외부 입력값에 대하여 검증 없이 화면에 출력될 경우 공격스크립트가 포함된 URL을 생성 할 수 있어
안전하지 않다.(Reflected XSS)
검색어 : <%=keyword%>
//게시판 등의 입력form으로 외부값이 DB에 저장되고, 이를 검증 없이 화면에 출력될 경우
공격스크립트가 실행되어 안전하지 않다.(Stored XSS)
검색결과 : $ {m.content}
<script type="text/javascript">
//외부 입력값에 대하여 검증 없이 브라우저에서 실행되는 경우 서버를 거치지 않는 공격스크립트가
포함된 URL을 생성 할 수 있어 안전하지 않다. (DOM 기반 XSS)
document.write("keyword:" + <%=keyword%>);
</script>
<% String keyword = request.getParameter("keyword"); %>
// 방법1. 입력값에 대하여 스크립트 공격가능성이 있는 문자열을 치환한다.
keyword = keyword.replaceAll("&", "&");
keyword = keyword.replaceAll("<", "<");
keyword = keyword.replaceAll(">", ">");
keyword = keyword.replaceAll("₩"", """);
keyword = keyword.replaceAll("'", "'");
keyword = keyword.replaceAll("/"", "/");
keyword = keyword.replaceAll("(", "(");
keyword = keyword.replaceAll(")", ")");
검색어 : <%=keyword%>
//방법2. JSP에서 출력값에 JSTL c:out 을 사용하여 처리한다.
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
검색결과 : <c:out value="$ {m.content}"/>
<script type="text/javascript">
//방법3. 잘 만들어진 외부 라이브러리를 활용(NAVER Lucy-XSS-Filter, OWASP ESAPI, OWASP Java-Encoder-Project)
document.write("keyword:"+
<%=Encoder.encodeForJS(Encoder.encodeForHTML(keyword))%>);
</script>
외부 입력값 파라미터나 게시판등의 form에 의해 서버의 처리 결과를 사용자 화면에 출력하는 경우,
입력값에 대해서 문자열 치환 함수를 이용하여 스크립트 문자열을 제거하거나,
JSTL을 이용하여 출력하거나, 잘 만들어진 외부 XSS 방지 라이브러리를 활용하는 것이 안전하다.
크로스사이트 스크립트의 경우 동작 상황에 따라 동일한 조치방법을 사용하면, 크로스사이트 스크립트 방지는 되더라도 원하는 동작이 정상적으로 되지 않을 수 있기 때문에, 잘 만들어진 외부 XSS방지 라이브러리를 이용하여 각 동작 상황에 따라 적절하게 사용하는 것을 권장한다.
string usrInput = Request.QueryString["ID"];
// 외부 입력 값이 검증 없이 화면에 출력 됩니다.
string str = "ID : " + usrinput;
Request.Write(str);
다음 C# 코드는 외부 입력값을 출력에 바로 사용하고 있다. 이는 XSS 공격을 유발 할 수 있다.
string usrInput = Request.QueryString["ID"];
string str = "ID : " + usrinput;
//AntiXss 패키지 등을 이용하여 외부 입력값을 필터링 합니다.
var sanitizedStr = Sanitizer.GetSafeHtmlFragment(str);
quest.Write(sanitizedStr);
AntiXss 패키지 등을 사용하여 XSS 공격을 예방할 수 있다.
int XSS(int argc, char* argv[]) {
unsigned int i = 0;
char data[1024];
…
// cgiFromString으로 받아온 사용자 입력값이 검증 없이 화면에 출력됩니다.
giFromString(“user input”, data, sizeof(data));
printf(cgiOut, “Print user input = %s<br/>”, data);
fprintf(cgiOut, “</body></html>₩n”);
return 0;
}
아래 C 코드 예제는 외부 입력값으로 사용자로부터 받은 입력값을 검증 없이 바로 cgi에 출력하는 화면이다.
cgiFromString(“user input”, data, sizeof(data));
// data에 위험한 문자열을 검사하는 코드를 추가한다.
if(strchr(p, ‘<’)) return;
if(strchr(p, ‘>’)) return;
…
fprintf(cgiOut, “Print user input = %s<br/>”, data);
fprintf(cgiOut, “</body></html>₩n”);
cgi에 출력하기 전에 사용자 입력값을 검증하여야 한다.