본문 바로가기
CS/시큐어 코딩

[시큐어 코딩] XSS(크로스 사이트 스크립팅)

by J-rain 2024. 5. 26.

 

XSS

공격자가 상대방의 브라우저에 스크립트가 실행되도록 해 사용자의 세션을 가로채거나, 웹사이트를 변조하거나, 악의적 콘텐츠를 삽입하거나, 피싱 공격을 진행하는 것을 뜻한다.

 

 

XSS 공격유형

Reflective XSS

공격자가 악성 스크립트가 포함된 URL을 클라이언트에 노출시켜 클릭을 유도하고, 쿠키 정보를 탈취하거나 피싱 사이트, 불법 광고 사이트로 이동하게 만든다.

서버에서 사용되는 외부 입력값 name이 안전한 값인지 검사하지 않고 사용되는 경우 XSS 취약점이 있는 처리 구조이다.

 

Reflective XSS 취약점 공격 처리 흐름인데 공격자가 악성 스크립트를 입력값으로 전달하도록 만들어진 URL을 사용자가 클릭하도록 유도하고 이 URL을 사용자가 클릭하면 해당 스크립트가 a.com서버의 ha.do 페이지로 전달되어 사용자에게 보내지는 응답의 일부로 사용된다.
응답으로 받은 스크립트 실행으로 인해 쿠키값이 유출되거나, 해당 사용자의 권한으로 웹 애플리케이션의 기능이 악용되거나 피싱 사이트로 유도되어 개인정보가 유출될 수 있다.

 

Stored XSS

악성 스크립트를 데이터베이스에 저장하여 해당 데이터베이스 정보를 이용하는 애플리케이션을 통해 시스템을 사용하는 모든 사용자들이 해당 스크립트를 실행하도록 만든다.

데이터베이스에 저장된 값을 읽어서 응답에 사용하는 경우, 그 값에 대한 XSS 취약점 검증을 수행하지 않고 그대로 사용하여 발생한다.

 

 

 

발생원인

JSP나 서블릿 코드에서 외부 사용자의 입력값이나 DB에서 검색한 결과값을 검증하지 않고 응답의 일부로 사용하여 발생한다.

 

 

 

 

공격기법

입력값을 출력에 사용하는 기능에서 Reflective XSS 발생 가능성 체크

 

게시판에 글쓰기와 같이 단문 이상의 입력이 가능한 부분에 실행 가능한 형태의 스크립트 태그를 입력해 실행할 수 있는지 확인한다.

 

 

1. XSS 공격 문자열 입력


경고창을 띄울 수 있는 스크립트를 입력값으로 서버에 전송하여, 기대하는 경고창이 실행되었다.

 

 

2. 필터링 우회 확인


URL 인코딩된 값을 입력하거나 대소문자를 섞어서 입력한 후 요청을 전송한 뒤, 스크립트가 실행되었다.

 

3. 쿠키 정보 획득이 가능한지 확인


보안 옵션이 클라이언트 PC에 설정되어 팝업만 뜨고있다.
쿠키 값이 외부로 유출되는 것을 막아주는 HttpOnly 해제

입력값에 쿠키값을 출력할 수 있는 스크립트를 작성하여 요청을 전송하여, 쿠키값이 출력되었다.

 

 

방어기법

입/출력 값에 필터링 적용

 

Reflective XSS와 Stored XSS 취약점을 동시에 제거하는 방법은 출력값에 대해 철저하게 필터링하는 방법이 있다. 하지만 이미 개발이 끝나 서비스를 실행하고 있는 시스템의 경우 출력값에 대해 필터링을 적용하기 위해 소스 코드를 수정하는 것은 쉽지 않은 일이다.

그래서 차선책으로 입력값에 대해 철저하게 필터링하여 안전한 값만 애플리케이션이 처리하도록 정책을 설정한다.

 

입력값에 대한 필터링을 적용하는 경우에는 HTTP 헤더, 쿠키, 쿼리 문자열, 폼 필드, 히든 필드 등 서버에 전달되어 사용될 수 있는 모든 인자들에 대해 정규식을 사용해 허용된 유형의 데이터만을 받아들이도록 입력값 검증을 실시한다.

 

XSS 취약점 제거를 위한 입력값/출력값 필터링 (ex. Spring MVC)

Spring MVC 환경

 

 

오픈소스 라이브러리 활용 XSS Filter

 

XSS Filter를 만드는 것은 쉽지않다. 필터를 우회하기 위해 각종 방식으로 인코딩되어 전달되는 데이터를 필터링하려면 인코딩 규칙까지도 충분히 감안하여 만들어야 하기 때문이다.

그래서 직접 XSS Filter를 만드는 것보다 이미 잘 검증된 필터를 활용하는 것을 권장한다.

 

네이버 개발자 그룹에서 생성하여 무료 배포하고 있는 자바 기반의 lucy-xss Filter를 간단하게 Controller 컴포넌트에 적용하여 동작 방식을 확인해보자.

 

 

TestController.java

	// Reflective XSS 테스트 
	@RequestMapping(value="/test/xss_test.do", method = RequestMethod.POST)
	@ResponseBody
	public String testXss(HttpServletRequest request) {
		StringBuffer buffer=new StringBuffer();
		String data=request.getParameter("data");
		buffer.append(data);
        return buffer.toString();	
	}

 

수정 TestController.java

import com.nhncorp.lucy.security.xss.XssFilter;


	// Reflective XSS 테스트 
	@RequestMapping(value="/test/xss_test.do", method = RequestMethod.POST)
	@ResponseBody
	public String testXss(HttpServletRequest request) {
		StringBuffer buffer=new StringBuffer();
		String data=request.getParameter("data");
		
		try {
			data=URLDecoder.decode(data, "UTF-8");
			System.out.println("Data: "+data);
		}catch(IOException e){
			System.out.println(e);
		}
		
		XssFilter filter =XssFilter.getInstance("lucy-xss-superset.xml");
		//buffer.append(data);
		buffer.append(filter.doFilter(data));
        return buffer.toString();	
	}
URL 인코딩되어 입력되는 값은 디코딩 후 Filter를 적용할 수 있도록하고 필터 객체를 생성한 뒤, 출력값에 대해 Anti-XSS 필터를 적용한다.

 

 


크로스 사이트 스크립팅 공격 차단 확인

 

 

 

 

 

 

 

참고: 해킹 방어를 위한 JAVA 시큐어코딩(실무에 바로 적용하는)(개정판 4판) 김영숙

댓글