제공: 한빛 네트워크
저자: Shreeraj Shah, 한동훈 역
원문: Detecting Web Application Security Vulnerabilities
코드 리뷰를 통한 웹 응용프로그램 취약점 발견
언어나 플랫폼에 관계없이 응용프로그램 소스 코드가 취약점의 주요 원인이다. CSI의 취약점 분포에 대한 조사에 따르면 프로그래밍 오류에 의한 취약점이 64%를 차지하며, 설정 문제가 36%에 이른다. IBM 연구소에 따르면 1,500 라인의 코드에 최소 한 개 이상의 보안 문제가 발생한다고 한다. 소스 코드 리뷰를 끊임없이 수행하는 한편, 취약점을 찾아내기 위해 웹 응용프로그램을 평가하고 감사하는 것이 필요하다.
문제 도메인
웹 응용프로그램 개발에 인기 있는 언어로는 액티브 서버 페이지(ASP), PHP, 자바 서버 페이지(JSP) 등이 있다. 모든 프로그래머는 객체를 구현하고, 작성하는 자신만의 방법을 갖고 있다. 이들 언어들은 프로그래머가 쉽게 개발할 수 있도록 API와 지시문(directive)을 제공한다. 불행히도, 프로그래밍 언어는 보안에 대해 어떠한 보장도 하지 못한다. 프로그래머가 작성한 코드가 다양한 공격 방법(attack vectors)에 대해 안전하다는 것을 보장하는 것은 프로그래거의 책임이다.
또한, 실제 시스템에 코드를 배포하기 전에 개발된 코드를 외부나 내부에서 보안 관점에 따라 평가하는 것은 필수다. 또한, 커스터마이징되는 응용프로그램, 프로그래머가 코딩하는 다양한 방법들이 존재하기 때문에 소스 코드에 존재하는 취약점을 결정하기 위해 한 가지 도구만 사용하는 것도 불가능하다. 소스 코드 리뷰에는 다양한 도구의 조합, 취약점을 찾아내기 위한 지능적인 분석(Intellectual Analysis)이 필요하다. 소스 코드는 매우 방대하며, 어떤 경우에는 수백, 수천만 라인에 이르기 때문에 제한된 시간안에 소스 코드 라인을 일일이 분석하는 것은 불가능하다. 때문에, 취약점 분석 도구가 필요하다. 도구는 정보(information)를 결정하는 데에만 도움을 줄 수 있다. 예를 들어, 이는 정보와 함께 연결해야 하는, 보안 잣대(security mindset)를 갖춘 지능(intellect)이다. 정보와 지능을 함께 사용하는 접근 방법은 소스 코드 리뷰에서 일반적으로 추천되는 방법이다.
가정(Assumption)
리뷰를 자동화하는 것을 설명하기 위해 ASP.NET으로 작성한 웹 응용프로그램 예제를 사용할 것이다. 소스 코드 분석 도구로는 파이썬 스크립트 예제를 만들었다. 여기서 설명하는 접근 방법은 어떤 언어로 작성된 웹 응용프로그램이든 적용할 수 있다. 또한, 다른 프로그래밍 언어를 사용해서 자신만의 도구를 작성하는 것도 가능하다.
방법론과 접근방법
내 경우에는 코드 리뷰 연습에 접근하는 나의 방법을 특정 목표를 가진 논리적인 단계로 나누었다.
- 의존성 결정
- 진입점(Entry Point) 식별
- 위협 매핑(Threat mapping) 및 취약점 발견
- 완화 작업(Mitigation) 및 대체 수단
의존성 결정
코드 리뷰 연습을 시작하기 전에 전체 아키텍처와 코드들의 의존성에 대해 이해할 필요가 있다. 이들을 이해하면 보다 나은 검토를 할 수 있으며, 핵심에 집중할 수 있다. 이 단계의 핵심 목표는 의존성을 명확히 밝혀내고, 이 정보를 다음 단계로 연결하는 것이다. 그림1은 검토에 사용할 사례 연구, 웹샵(web shop)의 전체 아키텍처를 표현한 것이다.
그림1. 웹 응용프로그램 아키텍처(webshop.example.com)
응용프로그램은 몇가지 의존성을 갖고 있다.
- 데이터베이스. 웹 응용프로그램은 벡엔드 데이터베이스로 MS-SQL 서버를 운영하고 있다. 코드 리뷰를 할 때 이 인터페이스도 조사해야 한다.
- 플랫폼 및 웹 서버. 응용프로그램은 닷넷 플랫폼 및 IIS 웹 서버에서 실행된다. 이는 두가지 관점에서 유용하다. 1) 배포를 안전하게 하는 것, 2) 소스 코드 종류와 언어를 결정하는 것
- 웹 리소스 및 언어. 이 예제에서 ASPX와 ASMX는 웹 리소스이다. 이들은 C#으로 작성된 전형적인 웹 응용프로그램과 웹 서비스 페이지를 의미한다. 이들 리소스는 코드 리뷰 동안 패턴을 결정하는 데 유용하다.
- 인증(Authentication). 응용프로그램 인증은 LDAP 서버를 사용해서 사용자를 인증한다. 인증 코드는 핵심 컴포넌트이며, 분석이 필요하다.
- 방화벽. 응용프로그램 레이어 방화벽이 있으며, 컨텐트 필터링이 활성화되어 있다.
- 서드파티 컴포넌트. 응용프로그램에서 사용하는 모든 서드 파티 컴포넌트는 분석이 필요하다.
- 인터넷으로부터의 정보 접근. 응용프로그램들이 인터넷으로부터 소비하는 RSS 피드나 이메일 같은 정보들도 고려해야 한다.
이러한 정보들을 알고 있으면, 코드를 이해하는 것이 보다 수월해진다. 다시 말해서, 전체 응용프로그램은 C#으로 작성되었으며, IIS를 운영하는 웹 서버에서 제공되고 있다. 바로 이것을 대상으로 할 것이다. 다음 단계는 응용프로그램의 진입점을 식별하는 것이다.
진입점 식별
이 단계의 목표는 웹 응용프로그램의 진입점(entry point)를 식별하는 것이다. 웹 응용프로그램은 다양한 위치(sources)로부터 접근될 수 있다(그림2). 따라서, 각 위치를 평가하는 것, 각 위치와 관련된 위험을 평가하는 것이 중요하다.
그림2. 웹 응용프로그램 진입점
이들 진입점은 응용프로그램에 정보를 제공한다. 이러한 값들은 응용프로그램에서 데이터베이스, LDAP 서버, 처리 엔진, 다른 컴포넌트들에 접근하다. 이러한 값들이 보호되지 않으면 응용프로그램에서 잠재적인 취약점이 열릴 수 있다. 관련된 진입점은 다음과 같다.
- HTTP 변수. 브라우저 또는 최종 클라이언트(end-client)에서 응용프로그램에 정보를 전송한다. 요청 정보들의 집함은 폼, 쿼리 스트링 데이터, 쿠키, 서버 변수(HTTP_REFERER 등)와 같은 다양한 진입점을 의미한다. ASPX 응용프로그램은 이들 데이터를 Request 객체로 사용한다. 코드 리뷰 연습 동안 이 객체의 사용을 살펴봐야 한다.
- SOAP 메시지. 응용프로그램은 SOAP 메시지 기반 웹 서비스에 접근할 수 있다. SOAP 메시지는 웹 응용프로그램에서 잠재적인 진입점이 될 수 있다.
- RSS 및 Atom 피드. 많은 신규 응용프로그램들은 서드 파티의 XML 기반 피드를 소비하고, 최종 사용자에게 다양한 포맷으로 출력을 표현한다. RSS와 Atom 피드는 XSS 또는 클라이언트측 스크립트 실행과 같은 새로운 취약점을 만들 수 있는 가능성을 갖고 있다.
- 서버로부터의 XML 파일. 응용프로그램은 인터넷을 통해 파트너들로부터 XML 파일을 소비할 수도 있다.
- 메일 시스템. 응용프로그램은 메일링 시스템으로부터 메일을 소비할 수도 있다.
위 목록은 사례 연구에서 사용하는 응용프로그램의 중요 진입점들이다. 다양한 파일들로부터 패턴을 추적하고 분석하고, 정규식을 사용해서 제출된 데이터에서 핵심 패턴을 찾아내는 것이 가능하다.
파이썬으로 코드 검사하기
scancode.py는 소스 코드 검색 유틸리티이다. 이 유틸리티는 리뷰 과정을 자동화해주는 간단한 파이썬 스크립트다. 파이썬 스캐너는 특정 목표를 수행하는 함수 3개로 구성되어 있다.
이 프로그램을 사용하는 것은 쉽다. 이 프로그램은 앞에서 설명한 함수들의 동작을 결정하는 몇 가지 스위치를 사용한다.
D:\PYTHON\scancode>scancode.py
Cannot parse the option string correctly
Usage:
scancode -
flag -sG : Global match
flag -sR : Entry points
flag -t : Variable tracing
Variable is only needed for -t option
예제:
scancode.py -sG details.aspx
scancode.py -sR details.aspx
scancode.py -t details.aspx pro_id
D:\PYTHON\scancode>
이 스캐너는 먼저 파이썬의 regex 모듈을 임포트한다.
import re
이 모듈을 임포트하면, 대상 파일에 대해 정규 표현식을 실행하는 것이 가능해진다.
p = re.compile(".*.[Rr]equest.*[^\n]\n")
이 라인은 정규 표현식을 정의한다. 여기서는 Reqest 객체 검색에 대한 정규식을 정의하고 있다. 이 정규식을 사용하고, match() 메서드는 파일에서 정규식 패턴과 일치하는 모든 인스턴스를 수집한다.
m = p.match(line)
진입점 검색
대상 코드에서 가능한 진입점을 찾기 위해 details.aspx 파일을 scancode.py로 검색해보자. -sR 스위치는 진입점을 찾기 위해 사용한다. detailas.aspx 페이지에 이를 실행하면 다음과 같은 결과를 생성한다.
D:\PYTHON\scancode>scancode.py -sR details.aspx
Request Object Entry:
22 : NameValueCollection nvc=Request.QueryString;
이 부분은 응용프로그램의 진입점이며, QueryString 정보는 NameValue 컬렉션 집합에 저장되는 위치이다.
다음 코드는 위 정보를 잡아두는 함수를 구현한 것이다.
def scan4request(file):
infile = open(file,"r")
s = infile.readlines()
linenum = 0
print "Request Object Entry:"
for line in s:
linenum += 1
p = re.compile(".*.[Rr]equest.*[^\n]\n")
m = p.match(line)
if m:
print linenum,":",m.group()
이 코드에서는 파일을 열어두고, 지정된 정규식 패턴을 사용해서 Request 객체를 잡아낸다. 이와 같은 접근 방법을 사용해서 다른 진입점들도 찾아낼 수 있다. 예를 들면, 다음 코드와 같은 방법을 사용해서 쿠키나 세션과 관련된 진입점을 식별해낼 수 있다.
# Look for cookie and session management
p = re.compile(".*.HttpCookie.*?[^\n]\n|.*.session.*?[^\n]\n")
m = p.match(line)
if m:
print "Session Object Entry:"
print linenum,":",m.group()
응용프로그램에서 진입점들의 위치를 찾아낸 후에는 취약점을 찾아보기 위해 이들을 추적하고 검색할 수 있다.
위협 매핑 및 취약점 발견
진입점을 발견하는 것은 위협 매핑(threat mapping)과 취약점 발견을 위해 범위를 좁힐 수 있게 해준다. 진입점은 추적에 있어 필수요소다. 응용프로그램에서 해당 변수가 실행 흐름을 따라 어디로 이동하는지, 미치는 영향이 어디인지 밝혀내는 것이 중요하다.
이전 검색은 응용프로그램에서 Request 객체 항목을 찾아냈다.
22 : NameValueCollection nvc=Request.QueryString;
스크립트를 -t 옵션과 함께 실행하면 변수를 추적하는 데 도움이 된다.(전체를 추적하려면 더 이상 추적가능한 것이 없을 때 까지 추적해야 한다)
D:\PYTHON\scancode>scancode.py -t details.aspx nvc
Tracing variable:nvc
NameValueCollection nvc=Request.QueryString;
String[] arr1=nvc.AllKeys;
String[] sta2=nvc.GetValues(arr1[0]);
이 코드는 값을 nvc에서 sta2로 할당하는 것을 알 수 있으며, sta2도 추적해야 한다.
D:\PYTHON\scancode>scancode.py -t details.aspx sta2
Tracing variable:sta2
String[] sta2=nvc.GetValues(arr1[0]);
pro_id=sta2[0];
여기서 pro_id 변수에 값이 할당되는 것을 발견했으므로 이에 대한 추적을 반복한다.
D:\PYTHON\scancode>scancode.py -t details.aspx pro_id
Tracing variable:pro_id
String pro_id="";
pro_id=sta2[0];
String qry="select * from items where product_id=" + pro_id;
response.write(pro_id);
마침내 변수를 끝까지 추적해냈다. 이 예제에서는 페이지 하나에 대해서 추적을 여러번 반복했지만, 응용프로그램간에 다양한 페이지를 이동하는 것을 추적하는 것도 가능하다. 그림3은 완전한 출력 결과를 나타낸 것이다.
그림3. 추적을 통한 취약점 발견
소스 코드와 그림에서 표시한 것처럼 소스에서 입력 검증이 없다. 즉, SQL 삽입 취약점이 존재한다.
String qry="select * from items where product_id=" + pro_id;
이 응용프로그램은 pro_id를 받아서 SELECT 문에 그대로 전달한다. SELECT 문을 조작하고, SQL 데이터에 삽입하는 것이 가능하다.
마찬가지로, 다른 라인은 크로스사이트 스크립팅(XSS) 취약점에 노출되어 있다.
response.write(pro_id);
검증되지 않은 pro_id 값을 브라우저에 전달하는 것은 공격자가 희생자(victim)의 브라우저에서 실행될 수 있는 자바스크립트를 삽입하는 것을 가능하게 한다.
스크립트의 -sG 옵션은 전체(Global) 검색 루틴을 실행한다. 이 루틴은 파일 객체, 쿠키, 예외 등을 검색한다. 각각은 잠재적인 취약점을 가지며, 이러한 검색은 취약점을 식별하고, 예상되는 위협에 매핑할 수 있다.
D:\shreeraj_docs\perlCR>scancode.py -sG details.aspx
Dependencies:
13 :
Request Object Entry:
22 : NameValueCollection nvc=Request.QueryString;
SQL Object Entry:
49 : String qry="select * from items where product_id=" + pro_id;
SQL Object Entry:
50 : SqlCommand mycmd=new SqlCommand(qry,conn);
Response Object Entry:
116 : response.write(pro_id);
XSS Check:
116 : response.write(pro_id);
Exception handling:
122 : catch(Exception ex)
이러한 코드 리뷰 접근 방법은 최소한의 노력으로 진입점, 취약점, 변수 추적을 할 수 있게 해준다.
완화작업 및 대체수단
취약점을 식별한 후에는 다음 단계로 위협(threat)을 완하(mitigate)시키는 것이다. 시스템의 배치에 따라 위협을 완하하는 다양한 방법이 있다. 예를 들어, 웹 응용프로그램 방화벽에 ", "과 같은 특정 문자 집합을 무시하는 규칙을 추가하는 것으로 SQL 삽입공격을 완화시키는 것도 가능하다. 이러한 문제를 완하시키는 가장 좋은 방법은 안전한 코딩 지침을 적용하는 것이다. 코드 레벨에서 변수를 사용하기 전에 적절한 입력값 검증을 하는 방법을 사용하는 것이다. SQL 레벨에서는 SQL SELECT 문 삽입공격을 피하기 위해 prepared statement나 저장 프로시저를 사용하는 것이 중요하다. XSS 취약점의 위협을 완화하기 위해서는 최종 클라이언트에 제공되는 컨텐트의 <과 >을 필터링하는 것이 필요하다. 이러한 조치들은 전체 웹 응용프로그램에 대한 위협을 경감시킨다.
결론
코드 리뷰는 취약점을 발견하고, 실제 소스를 이해하는 데 있어 매우 강력한 도구이다. 이를 "화이트박스(whitebox)" 접근방법이라 한다. 의존성 결정, 진입점 식별, 위협 매핑은 취약점을 발견하는데 도움이 된다. 이러한 모든 단계는 아키텍처 및 코드 리뷰가 필요하다. 코드는 본질적으로 복잡하며, 어떠한 도구도 필요한 것들을 모두 만족시킬 수 없다. 전문가로서 코드 리뷰를 수행할 때 필요한 도구들을 재빨리 작성할 필요가 있으며, 코드 베이스가 매우 클 때 이러한 도구들을 실행할 수 있어야 한다. 코드 라인을 일일이 살펴보는 것은 가능한 일이 아니다.
기사의 앞에서 논의한 것처럼, 접근 방법 중의 한 가지는 진입점에서 시작하는 것이다. 규모가 큰 소스 코드에서 다양한 패턴들을 뽑아내고 이들을 연결하기 위해 어떤 언어로 쓴 복잡한 스크립트 또는 프로그램을 작성할 수 있다. 변수 또는 함수를 추적하는 것은 전체를 탐색을 밝혀내고, 취약점을 발견하는데 큰 도움이 되게 하는 것이 핵심이다.
Exhibit 1 -
scancode.py
Shreerai Shah는 Net Square의 설립자이자 디렉터이며, Net Square의 컨설팅, 트레니잉, R&D 활동을 이끌고 있다.