본문 바로가기

Web Security/Secure Coding

시큐어 코딩 (Cross-Site Scripting)

XSS (Cross-Site Scripting) 이란? 

 웹 페이지에 악의적인 스크립트를 포함시켜 사용자 측에서 악의적인 실행되게 유도하는 것. 흔히 XSS 공격은 외부 입력에 대해 검증을 하지 않는 웹 사이트에서 게시판에 스크립트 삽입이 가능한 경우 주로 발생한다. 즉, 공격자가 악성 스크립트 구문을 포함하여 게시물을 업로드 한 후, 다른 사용자가 해당 게시물을 열람하는 경우 접속자의 권한으로 부적절한 스크립트가 수행되어 정보 유출 등의 공격이 발생할 수 있다. (XSS 공격은 흔히 다른 사용자의 쿠키를 탈취하는데 주로 사용된다.)

(Stored) XSS 공격 원리 

1. 공격자가 악성 스크립트를 포함한 게시물을 업로드 (Posting, 악성 스크립트가 서버에 저장됨)

2. 다른 유저가 해당 게시물을 열람 (Request) 

3. 웹 서버는 악성 스크립트가 포함되어 있는 게시물을 보여줌 (Response) 

4. 유저의 브라우저에서 악성 스크립트 실행 

 

게시판 업로드 코드 샘플을 예시로 살펴보자. 

[안전하지 않은 코드] 

import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletRequestWrapper; 

public class RequestWrapper extends HttpServletRequestWrapper {
    public void boardUpload(Connection con) { 
        // Connection con = DriverManager.getConnection("jdbc:mysql://{public dns or ip}:{port}/{database name}","{username}","{password}");
        String title = request.getParameter("title"); 
        String content = request.getParameter("content"); 
      
        Statement stmt = con.createStatement(); 
        String query = "INSERT INTO Board(title, content) VALUES('"+title+"','"+content+"')"; 
        stmt.executeUpdate(query);
           
        stmt.close(); 
    }
}

위 코드를 보면, 제목과 내용을 아무 필터링 없이 그대로 받아 데이터베이스에 데이터를 넣어주고 있다. 이와 같이, 게시물을 업로드 한 후, 웹 페이지에서는 SELECT 문을 통해 해당 게시물 정보를 가져오게 된다. 그러던 중, 다른 유저가 해당 게시물을 열람하려고 할 때, 게시물에 악성 스크립트문이 삽입되어 있을 경우 악성 스크립트가 실행되는 것이다. 

 

[안전한 코딩 기법] 

그러므로, XSS 공격을 막기 위해서는 이러한 악성 스크립트 구문을 넣을 수 없도록 '<', '>', '&', ',' 등의 특수 문자들을 필터링 해주어야 한다. 그러나, 만일 HTML 태그를 허용하는 게시판의 경우에는 게시판에서 지원하는 HTML 태그의 리스트를 선정한 후, 해당 태그만 사용할 수 있도록 해주어야한다. 추가적으로, 보안성이 검증되어 있는 API 를 사용하여 위험한 문자열을 제거해 줄 필요가 있다. 

 

[안전한 코드]

import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletRequestWrapper; 
// 보안 API 
import com.josephoconnell.html.HTMLInputFilter; 

public class RequestWrapper extends HttpServletRequestWrapper {
    public void boardUpload(Connection con) { 
        // Connection con = DriverManager.getConnection("jdbc:mysql://{public dns or ip}:{port}/{database name}","{username}","{password}");
        String title = request.getParameter("title"); 
        String content = request.getParameter("content"); 
      
        //Secure Coding (보안 API) 
        title = HTMLInputFilter().filter(title); 
        content = HTMLInputFilter().filter(content); 
      
        Statement stmt = con.createStatement(); 
        String query = "INSERT INTO Board(title, content) VALUES('"+title+"','"+content+"')"; 
        stmt.executeUpdate(query);
           
        stmt.close(); 
    }
}

 

위와 같이, 보안 API 인 HTMLInputFilter 를 사용하여 필터링 해주거나, replaceAll 메소드를 사용하여 특수 문자들을 제거해주면 XSS 공격을 막을 수 있다. 추가적으로, ESAPI.encoder().encodeForHTMLAttribute( argument ) 이러한 보안 API 도 존재한다.

 

 

참고 문헌

[1] 시큐어 코딩 보안 가이드 https://www.kisa.or.kr/public/laws/laws3_View.jsp?mode=view