문서의 이전 판입니다!


JSP 보안 개발 가이드

1절. 보안 대책

1. 스크립트 삽입 취약점

가. 취약점 상세 내용 및 보안 대책

Javascript, Vbscript 등 PC의 웹브라우저에서 실행되는 클라이언트 사이트 스크립트를 다른 사용자의 웹브라우저에서 실행하도록 함으로서 웹 브라우저를 제어하여 PC를 공격하는 취약점을 말한다. 공격에 사용되는 유형은 크게 두가지로 분류할 수 있다.

(1) Reflected XSS

이 유형의 XSS는 클라이언트 측에서 전송된 데이터가 서버측에서 즉시 처리된 후 사용자에게 응답으로 전송되는 돌아오는 경우에 해당한다. 다음과 같은 상황에서 발생이 가능하다.

  1. 검색 페이지에서 입력된 검색어가 검색 결과 페이지에 표시되는 경우
  2. URL에 포함된 특정 파라미터가 응답 페이지에 hidden 속성으로 포함되어 있는 경우

위의 두가지 유형은 본질적으로는 동일한 내용이다.
이러한 유형의 XSS 는 사회 공학적 방법 등을 통해서 공격 스크립트가 포함된 URL을 타인이 실행하도록 유도함으로서 (예를 들면 메신저로 링크를 전송하거나, 게시판에 URL을 링크로 걸어놓고 클릭을 유도하는 방식 등) 공격에 이용될 수 있다. 다만, 공격자가 강제적으로 타 사용자의 PC에서 공격 스크립트가 실행되도록 할 수는 없으므로 일반적으로 심각한 취약점으로 분류되지는 않는다.
그러나 공공기관이나 금융권과 같이 신뢰도가 중요한 대상인 경우에는 이 유형의 XSS 도 모두 제거해야 하며, 그 외에도 대외에 공개된 웹사이트라면 일반적으로 제거하도록 하는 것이 좋다.

(2) Stored XSS

게시판과 같이 사용자가 입력한 정보가 서버측 DB에 저장되어 있다가 타 사용자가 해당 정보를 열람할 때 DB에 저장되어 있는 정보를 가져와 화면에 출력하는 방식의 웹 애플리케이션에서 발생하는 취약점으로서, XSS의 가장 핵심적인 취약점이라고 할 수 있다. 불특정 다수를 대상으로 열람자의 웹브라우저에서 공격 스크립트를 실행할 수 있기 때문에 심각한 위협이 발생한다.
공격자가 XSS를 목적으로 악성 스크립트를 삽입하여 둘 수 있는 위치는 비단 게시판의 글 본문 뿐만 아니라 제목, 작성자 이름, 날짜, 첨부파일 이름 등이 모두 가능하며, 또한 게시판 외에도 사용자 프로필의 닉네임, 주소, 전화번호, 등 사용자가 입력이 가능한 모든 데이터에 스크립트가 삽입될 수 있다.

  • 게시판 : 제목, 본문, 작성자, 날짜, 첨부파일 이름, 태그, 분류 등
  • 사용자 프로필 : 이름, 닉네임, 주소, 전화번호, 이메일, 직업, 기타 입력정보
  • 기타 사용자가 입력 가능한 모든 데이터

나. 보안 대책

XSS에 대한 보안 대책은 적용할 대상에 따라 다음의 두가지 경우를 나누어 적용해야 한다. 먼저 태그를 사용할 필요가 없는 경우와 태그의 사용을 허용해야 하는 경우이다.

  • 태그를 사용할 필요가 없는 경우
    사내 게시판이나 reflected XSS의 경우와 같이 문자열 내에 HTML 태그를 허용할 필요가 없는 경우
  • 태그를 사용해야 하는 경우
    대외 고객용 게시판, 커뮤니티 게시판 등과 같이 사용자의 필요에 의해서 문자열 내에 태그를 사용해야만 하는 경우
(1) 태그를 허용할 필요가 없는 경우 (사내 게시판, Reflected XSS)

태그를 허용할 필요가 없는 사내 게시판 등 단순 게시판의 경우는 사용자가 입력하는 모든 데이터에서 <, > 문자를 HTML Special Character 로 인코딩 함으로서 XSS를 완전히 차단할 수 있다. HTML Special Character 로 인코딩 된 코드는 웹브라우저에서 화면에 출력될 때는 정상적인 문자열로 출력되지만, 태그나 스크립트로서는 작동하지 않기때문에 XSS 로부터 안전하게 된다.

인코딩 대상 문자 HTML Special Character 코드
< &lt;
> &gt;


Reflected XSS 는 화면에 표시되는 모든 변수값들 (hidden field 포함)에 대해서 발생 가능하므로 모든 출력값에 대한 검증이 수행되어야 한다.

JSP

따로 제공하는 인코딩 함수가 없으므로 직접 replace 문을 통해 <, > 를 필터링하는 함수를 작성하여 사용한다.

resultStr = resultStr.replaceAll("<", "&lt;");
resultStr = resultStr.replaceAll(">", "&gt;");

한편, jsp 에서는 프리젠테이션 페이지를 작성할 때, JSTL 을 사용하면 모든 출력값이 자동으로 인코딩되므로 따로 replace를 할 필요가 없으므로 편리할 수 있다. (개발 단계라면 권고할 만 함)

<c:out value="${value}" />
(2) 태그를 허용해야 하는 경우 (공개 게시판)
게시판의 태그 허용에 대한 대응

공개 게시판과 같은 커뮤니케이션 중심의 웹 애플리케이션에서는 사용자들이 게시물을 꾸미거나 링크, 이미지, 동영상 등의 사용을 원하기 때문에 HTML 태그를 완전히 금지할 수 없다. 따라서 <, >를 필터링하되, 사용자가 사용해야하는 태그에 대해서는 <, > 를 필터링해서는 안된다.
따라서 웹사이트 운영자는 자신의 게시판에서 사용자에게 허가할 최소한의 HTML 태그를 선별한 후, 각각의 태그들에 대해서만 역변환 (즉, &lt;, &gt; 등으로 replace 된 <, >를 다시 원래대로 되돌리는 것)해야 한다.
또한 해당 태그들을 허용할 경우 발생 가능한 위협들에 대해서 대처하기 위한 별도의 방어 코드를 추가로 작성해야 한다. 방어 코드는 다음의 두 가지 방식을 적용할 수 있다.

가. 단어 blacklist 를 필터링 하는 방식

이 방식은 XSS 공격에 자주 사용되는 단어를 필터링하여 사용할 수 없도록 하는 방식이다
이 방식은 구현하기가 간단하지만, blacklist에 포함되지 않는 코드가 공격에 사용될 경우 막을 수 없으며, 또한 필터링 우회 기법이 발전함에 따라 필터링 자체가 우회될 가능성이 있다. 또한 blacklist로 선정된 단어를 사용자가 게시물에 사용할 수 없다는 단점이 있다.

blacklist 코드 예
// blacklist 를 필터링하여 사용할 수 없도록 함
test_str_low= test_str.toLowerCase();
test_str = test_str_low;
test_str = test_str.replaceAll("javascript", "x-javascript");
test_str = test_str.replaceAll("script", "x-script");
test_str = test_str.replaceAll("iframe", "x-iframe");
test_str = test_str.replaceAll("document", "x-document");
test_str = test_str.replaceAll("vbscript", "x-vbscript");
test_str = test_str.replaceAll("applet", "x-applet");
test_str = test_str.replaceAll("embed", "x-embed");  // embed 태그를 사용하지 않을 경우만
test_str = test_str.replaceAll("object", "x-object");    // object 태그를 사용하지 않을 경우만
test_str = test_str.replaceAll("frame", "x-frame");
test_str = test_str.replaceAll("grameset", "x-grameset");
test_str = test_str.replaceAll("layer", "x-layer");
test_str = test_str.replaceAll("bgsound", "x-bgsound");
test_str = test_str.replaceAll("alert", "x-alert");
test_str = test_str.replaceAll("onblur", "x-onblur");
test_str = test_str.replaceAll("onchange", "x-onchange");
test_str = test_str.replaceAll("onclick", "x-onclick");
test_str = test_str.replaceAll("ondblclick","x-ondblclick");
test_str = test_str.replaceAll("enerror", "x-enerror");
test_str = test_str.replaceAll("onfocus", "x-onfocus");
test_str = test_str.replaceAll("onload", "x-onload");
test_str = test_str.replaceAll("onmouse", "x-onmouse");
test_str = test_str.replaceAll("onscroll", "x-onscroll");
test_str = test_str.replaceAll("onsubmit", "x-onsubmit");
test_str = test_str.replaceAll("onunload", "x-onunload");
}
나. 태그의 property를 검증하는 방식

사용을 허가할 각각의 태그들에 대해서 property 들에 대해 개별적으로 유효성 검사를 실시하여 정상적이지 않은 방식으로 사용된 property를 걸러내는 방식이다. 이 방식은 구현하기가 좀더 복잡하지만 허가되지 않은 모든 형태의 입력을 거부하는 방식이므로 우회될 가능성이 낮아 보다 안전하며, 필터링이 사용자의 게시물의 내용을 손상시키지 않는 장점이 있다.
예를 들면 <img> 태그에 대해 다음과 같은 규칙을 적용하여 규칙이 위반된 property는 모두 삭제하는 방식이다.

img 태그의 허가 규칙
- img 태그는 property에 src, width, height 만 허용(그 외의 모든 property 는 무시)
- src 는 http://- 로 시작하는 이미지 파일 경로만 허용 (확장자로 . jpg .gif 등만 허용)
- width, height 의 값은 숫자만 허용

이 방식의 대책을 적용하기 위해서 고려해야 할 요소들은 다음과 같다.

  • 최소한의 HTML 태그만 허용한다
  • 각 태그별로 필수적인 프라퍼티만 허용한다
  • onClick, onerror 등 이벤트 유형의 프라퍼티는 허용하지 않는다
  • 각 프라퍼티에 삽입되는 데이터의 형식을 엄격하게 제한한다. (예 : “src” 프라퍼티에 URL 주소만 입력 가능해야 하며 “javascript:alert(‘test’);” 등과 같은 내용이 입력되어서는 안됨)

새로운 HTML 규약의 개발, 웹브라우저의 발전 등으로 인해 XSS 공격 패턴은 계속 새로운 패턴이 개발될 것이기 때문에, XSS 에 대한 필터링 로직 역시 지속적으로 테스트되고 수정되어야 할 필요가 있다.

2. SQL Injection 취약점

가. 취약점 상세 내용 및 보안 대책

웹 사이트는 DBMS와 연동하므로 웹 어플리케이션에서 사용자의 입력값을 통하여 데이타 트랜잭션이 발생함. 만일 사용자 입력값에 대한 유효성 검증이 누락될 경우, 악의적인 사용자는 정상적인 입력값 대신 SQL 쿼리문이 포함된 조작된 입력값을 전송하여 서버측 쿼리문의 구조를 변경할 수 있으며, 이를 통해서 사용자 인증을 우회하거나 데이터베이스의 정보를 유출시키고 서버의 시스템 명령어를 실행시킬 수도 있음.

나. 보안 대책

(1) Database 운영 레벨에서 SQL Injection 방어 대책

DB 또는 웹사이트 운영자가 SQL Injection을 방어하기 위해서는 기본적으로 다음과 같은 사항에 유의하여 관리가 필요하다.

  • DB 계정에 최소 권한 부여
    • 웹사이트에서 사용되는 DB 계정에 최소한의 권한만 부여해야 함
    • DB 계정에 system 권한 (sysdba, sa, root 등)을 부여해서는 안됨
  • 에러 노출 방지
    • 에러 발생시 웹서버 또는 WAS 에서 정형화된 에러 페이지를 출력하도록 설정하여 에러에 의한 DB 정보 노출을 방지함
  • SQL Server의 경우 xp_cmdshell 확장 프로시저를 제거함

그러나 위와 같은 방법만으로는 SQL Injection을 방어할 수 없으므로 다음과 같이 소스코드 레벨에서 취약점을 제거하기 위한 대책을 적용해야 한다.

(2) 소스코드 레벨에서 Prepared Statement 구문을 통한 SQL Injection 방어

웹사이트가 개발중에 있다면 DAO 객체 또는 DB 연결 구문에서 Prepared Statement 구문을 이용하여 DB 트랜잭션을 처리함으로서 SQL Injection 취약점이 근본적으로 발생하지 않는 구조로 웹사이트를 개발해야한다.
Prepared Statement 구문은 SQL 쿼리를 선처리하여 컴파일 한 후, 이후 입력되는 변수값을 항상 문자열 변수로 다루기 때문에 사용자가 어떤 악의적인 SQL 구문을 변수에 삽입해도 SQL 문에 영향을 미치지 않아 SQL Injection이 발생하지 않는다.

JSP 에서 Prepared Statement 구문 사용

Jsp 에서 prepared Statement 구문을 구성하는 간단한 예시는 다음과 같다.

prepared Statement 구문
// 객체 선언
Connection con;
PreparedStatement pstmt;
ResultSet rs;

// DB연결 생성
con = DriverManager.getConnection(-------);

// Query 문 및 변수값 세팅
pstmt = con.prepareStatement(“Select  name, id, num from Membertable where id=? And passwd=?“);
pstmt.setString(1, "test");             // 변수형에 따라 setXXXX 사용 ex) setInt, setDouble
pstmt.setString(2, "testpwd");

// Query 문 실행
rs = pstmt.executeQuery();          // executeQuery, executeUpdate

// 결과 처리
if (rs.next()){
	// rs 객체로부터 칼럼 이름을 이용한 결과값 추출하여 사용자 펑션의 실행
	Run_user_function (…, rs.getString(name), rs.getString(id), rs.getint(num));
	// 또는 인덱스를 이용한 결과값 추출
	Run_user_function (…, rs.getString(1), rs.getString(2), rs.getint(3));

}

// 객체 close
rs.close();
pstmt.close();

※ 참고 : 저장 프로시저를 이용하여 DB 트랜잭션을 처리하는 방법 역시 prepared statement 구문과 동일한 효과를 기대할 수 있다.

(3) 소스코드 레벨에서 필터링 코드를 통한 SQL Injection 방어

만일 이미 운영중인 웹사이트에서 DB 트랜잭션 처리를 Prepared Statement 구문으로 수정하는 것이 어려울 경우, 차선책으로 특수 문자 및 Query 문자열에 대한 필터링을 통해서 SQL Injection 이 발생하지 않도록 해야 한다.
사용자측으로부터 전달되는 파라메터 중 DB 쿼리문에 사용되는 모든 파라미터 (게시판 ID, 글 번호, 검색 keyword, 사용자 번호, 항목 번호, 분류명칭 등)로부터 입력되는 데이터에 대하여 아래와 같이 특수 문자 및 Query 예약어를 필터링해 에러 처리를 하거나 ‘\’ 문자 또는 공백 문자로 치환한다.

필터링 할 특수 문자 및 구문
' union
select
insert
# drop
( update
) from
; where
@ join
= substr (oracle)
* user_tables (oracle)
/ user_table_columns (oracle)
+ subsring (ms-sql)
information_schema (mysql) sysobjects (ms-sql)
table_schema (mysql) declare (ms-sql)
JSP 에서 필터링 샘플 코드
필터링 샘플 코드
// 특수문자 필터링을 위해 특수문자를 정의
Pattern evilChars = Pattern.compile("['\"\\-#()@;=*/+]");
// 특수문자는 모드 공백으로 치환
test_str = evilChars.matcher(test_str).replaceAll("");

// 특수 구문 필터링 (데이터베이스가 Oracle 인 경우)
test_str_low= test_str.toLowerCase();
if(test_str_low.contains("union") || test_str_low.contains("select") || test_str_low.contains("insert") || test_str_low.contains("drop") || test_str_low.contains("update") || test_str_low.contains("delete") || test_str_low.contains("join") || test_str_low.contains("from") || test_str_low.contains("where") || test_str_low.contains("substr") || test_str_low.contains("user_tables") || test_str_low.contains("user_tab_columns"))
{
test_str = test_str_low;
test_str = test_str.replaceAll("union", "q-union");
test_str = test_str.replaceAll("select", "q-select");
test_str = test_str.replaceAll("insert", "q-insert");
test_str = test_str.replaceAll("drop", "q-drop");
test_str = test_str.replaceAll("update", "q-update");
test_str = test_str.replaceAll("delete", "q-delete");
test_str = test_str.replaceAll("and", "q-and");
test_str = test_str.replaceAll("or", "q-or");
test_str = test_str.replaceAll("join", "q-join");
test_str = test_str.replaceAll("substr", "q-substr");
test_str = test_str.replaceAll("from", "q-from");
test_str = test_str.replaceAll("where", "q-where");
test_str = test_str.replaceAll("declare", "q-declare");
test_str = test_str.replaceAll("openrowset", "q-openrowset");
test_str = test_str.replaceAll("user_tables","q-user_tables");
test_str = test_str.replaceAll("user_tab_columns","q-user_tab_columns");
test_str = test_str.replaceAll("table_name","q-table_name");
test_str = test_str.replaceAll("column_name","q-column_name");
test_str = test_str.replaceAll("row_num","q-row_num");
}

3. 파일 업로드

가. 취약점 상세 내용 및 보안 대책

첨부 파일 업로드 기능이 있는 게시판 등에서 실행 가능한 확장자를 가진 스크립트 파일의 업로드가 허용되는 경우, 공격자에 의해 악성 프로그램이 업로드 되어 실행 될 수 있음.
공격자는 첨부한 악성 프로그램을 실행하여 웹 서버 사용자 권한 획득한 후 내부 네트워크로의 침입을 시도하거나 DB 에 연결하여 중요 정보를 유출시킬 수 있음.

나. 보안 대책

(1) 서버 운영 관점의 보안 대책

서버 운영 관점에서 아래와 같은 대책을 적용함으로서 소스코드 상의 취약점에 의해서 악성 파일이 업로드 되더라도 공격자가 이를 실행할 수 없도록 함으로서 업로드 취약점에 의한 피해를 최소화 해야 한다.

  • 파일이 업로드 되는 디렉토리의 스크립트 실행 권한을 제거함
  • 업로드 디렉토리를 서버측 디렉토리 구조에서 웹루트 디렉토리 (예: Apache 의 DocumentRoot)의 서브 트리 바깥에 위치시킴으로서 사용자측 웹브라우저에서 URL을 통해서 업로드 디렉토리에 직접 접근할 수 없도록 구성
(2) 소스코드 관점의 보안 대책

웹 애플리케이션의 소스코드에서 아래와 같이 실행 가능한 파일들이 서버에 업로드 할 수 없도록 필터링하여 제한하는 모듈을 추가해야 한다.

ASP .asa, .asp, .cdx, .cer, .htr, .aspx
JSP .jsp, .jspx
PHP .html, .htm, .php, .php3, .php4, .php5

위의 표에서 제시된 확장자 목록들은 일반적인 설정 환경에 해당되는 목록이지만, 각 서버측 스크립트 엔진에서 실행 가능한 것으로 인식하는 확장자의 종류는 각각의 서버측 설정에 따라 다르다. 따라서 만일 별도로 등록한 실행 가능 확장자가 있다면 제한 목록에 추가해야 한다.
한편, 실제로 필터링 로직을 구현할 때, black list 방식의 필터링 (제한할 목록 외에는 모두 허용하는 방식) 으로 구현할 경우, 제한할 keyword의 누락 가능성이 존재하고 또한 문자열 인코딩 등을 통해서 필터링의 우회가 가능할 수 있기 때문에 일반적으로 더 안전한 white list 방식의 필터링이 권장된다.
white list 방식의 필터링은 허용할 확장자 목록(예: .jpg, .doc, .xls 등) 만을 확정 선정하고 그 외의 모든 확장자를 제한하는 방식의 필터링이다.

확장자 필터링 로직은 일반적으로 다음과 같은 원칙에 따라 구현되어야 한다.

  • 필터링은 반드시 Server Side 에서 구현해야 함
  • 파일의 확장자 검사를 할 때 문자열을 이용한 trick에 의해서 필터링이 우회되지 않도록 신중하게 구현해야 함
    • 대소문자 구분없이 비교 또는 Lower case 로 일괄 변경하여 비교 (test.JsP, test.jsP 등)
    • 파일명의 가장 우측에 있는 확장자를 비교함으로서 “test.gif.jsp”, “test.jsp.”, “test.jsp;test.jpg” 등의 방식으로 필터링이 우회되지 않도록 구현
  • 업로드되는 파일을 저장할 때, 파일명과 확장자를 추측할 수 없는 무작위 문자열 및 실행 불가능한 확장자로 변경하여 저장함. (권장 사항)
  • 저장 경로 및 파일명은 DB에 저장한 후, index 번호를 통해서 호출하도록 함으로써 파일명 및 경로를 외부에 노출되지 않도록 함. (권장 사항)

위에서 마지막 두가지 적용 항목은 구현시 복잡한 로직의 변경이 요구되므로 이미 운영되고 있는 서버의 경우 필수적인 항목은 아니다. 그러나 금융권과 같이 완벽한 보안을 추구해야만 하는 곳이거나 개발 단계에서 보안이 고려되는 경우는 위의 두가지 로직을 적용하도록 권고해야 한다.

JSP 에서 소스 코드 보안 대책
  • 파일 확장자 추출 코드 예시
파일 확장자 추출 코드 예시
<%
   String filePath = "/test/test.jsp";
String fileExt = filePath.substring(filePath.lastIndexOf('.') + 1).toLowerCase();
%>
  • Black List 방식의 필터링 코드 예시
    Windows 서버에서 동작하는 JSP의 경우는 ”;(세미콜론)” 파싱 관련 취약점이 발생할 수 있으며 Black List 방식의 필터링의 경우는 “.(dot)” 관련 문제점이 발생할 수 있으므로 이에 대한 처리 코드를 포함해야 한다. (Unix에서 동작하는 Jsp는 관련 없음)
Black List 방식의 필터링 코드 예시
<%

Boolean checkResult = true;

// 업로드 금지 확장자 리스트
String blockExt[] = {"jsp","jspx"};

// 금지할 확장자 체크
for(int i=0; i<blockExt.length;i++) {
if( blockExt[i].equals(fileExt) ){
checkResult = false;
break;
    }
}

// Windows일 경우 (.) 및 세미콜론 파싱 오류 관련 처리
if(fileExt.length() == 0 ) {
checkResult = false;
}
if(filePath.contains(";")) {
checkResult = false;
}

if(checkResult == false){
out.println ("업로드가 금지된 파일 입니다.");
}else{
out.println ("업로드가 허용된 파일 입니다.");
}

%>
  • White List 방식 필터링 코드 예시
    Windows 서버에서 동작하는 JSP의 경우는 ”;(세미콜론)” 파싱 관련 취약점이 발생할 수 있으므로 이에 대한 처리 코드를 포함해야 한다. (Unix에서 동작하는 Jsp는 관련 없음)
White List 방식 필터링 코드 예시
<%

Boolean checkResult = false;

// 업로드 허용 확장자 리스트
String allowExt[] = {"doc","docx","xls","xlsx","jpg","gif","txt"};

// 허용할 확장자 체크
for(int i=0; i<allowExt.length;i++) {
if( allowExt[i].equals(fileExt) ){
checkResult = true;
break;
    }
}

// Windows일 경우 세미콜론 파싱 오류 관련 처리
if(filePath.contains(";")) {
checkResult = false;
}

if(checkResult == false){
out.println ("업로드가 금지된 파일 입니다.");
}else{
out.println ("업로드가 허용된 파일 입니다.");
}

4. 파일 다운로드

가. 취약점 상세 내용 및 보안 대책

Web Application 의 download 관련 모듈의 파라미터에 path traversal 문자열을 삽입하여 웹 루트 디렉토리의 상위 경로에 위치하는 OS파일 시스템까지 접근할 수 있으며, 이를 이용해서 시스템의 각종 중요 파일 및 웹 프로그램의 소스 코드를 다운로드할 수 있음.

나. 보안 대책

파일 다운로드 취약점으로부터 안전하기 위해서는 다운로드 모듈을 다음과 같이 구현하도록 일반적으로 권고된다.

  • 파일 다운로드 모듈 구현시 실제 파일 경로는 DB에 저장하도록 하고 사용자에게 노출되는 URL의 파라미터에는 인덱스 번호를 통해 다운로드 할 파일을 표시함으로서 사용자에게 조작을 시도할 수 있는 경로 정보가 노출되지 않도록 구현함

그러나 위의 방식으로 구현하기 위해서는 웹사이트 로직을 수정하는 데 다소 복잡한 작업이 필요하다. 따라서 공공기관이나 은행권 사이트와 같이 정보 노출에 매우 민감한 사이트를 제외한 내부 직원용 포털 등의 사이트에서는 차선책으로서 다음과 같은 필터링 코드를 적용하여 취약점을 해결하도록 한다.

  • 파일 다운로드 모듈 구현시 파일 경로를 처리하는 파라미터 변수에서 디렉토리 상위 경로를 의미하는 path traversal 문자열을 필터링하여 사용할 수 없도록 함
    (필터링할 문자열 : [..], [../], [..\],)
  • 다운로드를 허용할 디렉토리를 지정하여 해당 디렉토리를 벗어나는 위치의 다운로드 요청에 대해서는 경고메시지와 함께 다운로드를 금지하도록 함
JSP 에서 필터링 코드의 구현 예시
필터링 코드의 구현 예시
<%
// 다운로드 허용할 디렉토리 설정
String allowPath = "/server/upfiles/";

// 파라미터로부터 다운로드할 파일을 입력 받아 전체 경로를 생성함
String inputPath = getParameter("downfile");
String filePath = allowPath + inputPath;

// 금지 문자열 리스트
String blockchar[] = {"..", "../", "..\\"};

Boolean checkResult = true;

// 금지할 문자열 포함 여부 체크
for(int i=0; i<blockchar.length;i++) {
if( filePath.indexOf(blockchar[i]) != -1 ){
checkResult = false;
}
}

// 파일 전체 경로로부터 디렉토리 경로만 추출한 후, 다운로드 허용된 디렉토리인지 체크
String path = filePath.substring (0, filePath.lastIndexOf("/") + 1).toLowerCase();
if( !path.equals(allowPath) ){
    checkResult = false;
   }

if(checkResult == false){
out.println ("다운로드가 금지된 파일 입니다.");
}else{
out.println ("다운로드가 허용된 파일 입니다.");
}

%>

5. URL 강제 접속 / 인증 우회

가. 취약점 상세 내용 및 보안 대책

모든 웹페이지는 개별적으로 인증 및 권한 관리 모듈을 포함하고 있어야 한다. 그렇지 않을 경우 인증받지 않은 사용자가 해당 페이지의 URL 을 직접 입력하여 강제 접속할 수 있다.
또한 인증 및 권한 모듈은 반드시 안전한 방식으로 구현되어야 하며, 만일 인증 및 권한 관리 로직이 취약하여 우회가 가능하거나 권한 관리가 제대로 이루어지지 않는 경우, 불법적인 접근이나 허가받지 않은 Role 의 허용으로 중요 정보의 유출, 서비스의 무단 사용 등 심각한 문제가 발생할 수 있다.

나. 보안 대책

URL 강제 접속 또는 인증 우회 취약점은 웹사이트의 인증 및 권한 관리 모듈의 취약점으로 인해 발생하게 된다.
이를 해결하기 위해서는 웹사이트의 모든 페이지에 대해서 개별적으로 적절한 인증 및 권한 검증이 수행되어야 하므로 일반적으로 인증 및 권한 관리를 담당하는 공통 모듈을 작성하여 각 페이지에 삽입하는 방식으로 구현하는 경우가 많다.
인증 및 권한 관리 모듈에서 발생하는 취약점의 주요 원인은 다음과 같다.

  • 인증 및 권한 관리 모듈이 존재하나 특정 페이지에 누락되어 있는 경우
  • 인증 및 권한 관리 모듈의 구현에 취약점이 존재하여 이에 대한 우회가 가능한 경우
(1) 특정 페이지에 인증 및 권한 관리 모듈이 누락된 경우

인증 및 권한 관리 모듈이 이미 존재하지만 특정 페이지에만 해당 모듈의 적용이 누락된 경우는 공통 모듈을 페이지에 추가하는 것으로 해결할 수 있다.
그러나 이러한 유형의 취약점은 여러 페이지에서 복수로 발견되는 경우가 일반적이기 때문에 취약점 진단(또는 모의해킹)에서 모든 페이지에 대한 전수 검사를 진행하지 않은 이상은 공통 인증 모듈이 누락된 페이지들 중에서 아직 발견되지 않은 경우가 존재할 가능성이 높다.
따라서 웹사이트 운영자 담당자 또는 유지보수 개발사는 이 취약점을 해결할 때 취약점이 보고된 특정 위치 뿐만 아니라 웹사이트의 모든 페이지에 대해서 검토를 실시할 것을 권고한다. 각각의 페이지에 대해서 다음 사항을 검토하도록 한다.

  • 이 페이지는 접근시 인증이 필요한 페이지 인가?
  • 이 페이지에 접근하는 모든 유저에 대해서 인증 및 권한이 적절하게 검사되고 있는가?
(2) 인증 및 권한 관리 모듈에 취약점이 발생하여 우회가 가능한 경우

인증 및 권한 관리 모듈의 취약점은 각 사이트마다 다양한 형태가 나타나지만 일반적으로 다음과 같은 사항들에 유의하여 모듈을 설계 및 수정함으로서 취약점을 보완하도록 한다.

  • 인증 및 권한의 허용의 초기값은 default 로 모든 경우에 deny 로 설정 후, 필요한 권한을 부여받은 유저에 대해서만 해당 권한을 allow 하는 방식으로 구현함
  • Role based 권한 관리를 구현할 때, 접근 권한이 없는 메뉴나 링크를 단순히 화면에 표시하지 않는 방식으로만 구현한 후, 각 페이지의 권한 검증을 누락하게 되면 URL 강제 접속에 취약하게됨. 메뉴나 링크를 화면에 표시하지 않는 것과는 별도로 반드시 모든 페이지에서 권한을 검증해야 함
  • 특정 권한이 요구되는 작업이 일련의 flow를 통해서 수행되는 경우, 해당 flow의 중간 단계를 포함한 모든 작업 단계에 대해서 인증 및 권한 검증이 이루어져야 함 (예 : 게시판의 글 수정은 form 페이지에서 내용을 입력받은 후 action 페이지에서 데이터 업데이트를 처리하고 view 화면으로 전환하는 flow로 이루어 지는데, form, action, view 페이지에서 모두 인증 및 권한 검증이 별도로 이루어져야 함)
  • 권한 없는 페이지에 대한 접근 시도가 발생했을 때 “location.href=’/error/accessDeny.jsp’” 와 같은 형태로 javascript에 의해 페이지를 Redirection 처리 하는 방식으로 구현하는 경우, Redirection 스크립트 코드가 실행되는 페이지는 접근이 거부된 페이지의 정상적인 내용을 포함해서는 안됨

가. 취약점 상세 내용 및 보안 대책

Cookie는 HTTP 프로토콜의 비연결성 특징을 고려하여 사용자 Session 관리의 편의성을 도모하기 위해 사용되는 기술적 방법이며, 주로 웹사이트의 설정값을 저장하여 각 사용자가 웹사이트에 접속할 때 동일한 설정을 유지하거나 또는 사용자의 인증과 관련된 정보를 처리하기 위해 사용된다.
그러나 Cookie 근본적으로 Client Side Session 기술로서 전달되는 값에 대한 사용자의 조작이 가능한 문제가 있기 때문에 Cookie 의 변수에 중요한 정보를 포함하여 사용하는 경우 Client 측 웹브라우저의 조작을 통해서 해당 값을 변조하여 인증을 우회하거나 타 사용자의 정보를 도용하는 등의 취약점이 발생할 수 있다.
또한 Cookie 로 전달되는 변수는 GET / POST 를 통해서 전달되는 변수와 동일하게 SQL Injection 및 파라미터 조작 등의 공격에 영향을 받을 수 있다.

나. 보안 대책

(1) Session 방식의 사용

평문 정보를 Cookie 변수에 저장하여 서버와 클라이언트 간에 전달하는 일반적인 방식의 Cookie 활용은 더 이상 권장되지 않는다.
WAS와 같은 서버측 스크립트 엔진은 Cookie 보다 발전된 형태인 Session 방식의 상태값 전달 방식을 지원한다. Session 방식은 서버측의 저장 공간에 각 사용자별로 인증 정보나 설정값 등 특화된 정보를 저장할 수 있는 저장소를 지원하며 암호화된 Cookie 변수를 통해 이를 식별하게 하는 방식으로 이루어져 있으므로 Client 측에서 정보의 변조가 불가능하며, 따라서 Cookie 방식보다 안전하다.
따라서 인증이나 권한 정보와 같이 변조되어서는 안되는 중요한 정보는 가능한 Session 방식을 이용하여 구현하는 것이 바람직하다.

만일 Cookie 변수에 데이터를 저장하여 전송할 필요가 있는 경우, 해당 정보가 인증 및 권한 등 중요한 정보일 경우 평문으로 사용해서는 안되며 반드시 SEED, 3DES, AES등 공인된 암호화 알고리즘을 사용하여 정보를 암호화한 후 사용해야 한다.
또한, 중요한 정보가 아니라고 해도, Cookie 변수를 통해서 전달되는 변수값은 GET/POST 파라미터 변수와 마찬가지로 SQL Injection, XSS, 파라미터 조작 등과 같은 공격에 영향을 받기 때문에 각각의 취약점을 방어하기 위한 적절한 입력값 검증이 수행되어야 한다.

  • Cookie 변수로 전달된 값이 DB와 연동하는 로직으로 전달되어 사용되는 경우 반드시 SQL Injection 공격을 차단하기 위한 대응책을 적용해야 함
  • Cookie 로 전달되는 변수가 장바구니, 결재 모듈 등 웹사이트의 중요한 로직에서 사용되는 경우, 변수의 변조 가능성에 대비한 적절한 유효성 검증이 수행되어야 함

7. URL 파라미터 조작

가. 취약점 상세 내용 및 보안 대책

공격자는 웹 URL의 GET/POST 파리미터 또는 HTML 코드의 <INPUT> 변수, Hidden field, javascript 변수 등에서 노출되는 데이터를 통해서 서버측 프로그램의 로직 및 역할 등을 유추할 수 있다. 또한 해당 변수의 값을 고의적을 변조하여 특정한 값을 입력하여 전송하므로서 서버측 프로그램이 자신이 원하는 특정 작업을 수행하도록 조작을 시도할 수 있다.
만일 웹사이트 로직이 신중하계 설계되지 않는다면 공격자가 전송한 조작된 입력값에 의해서 서버측 프로그램이 의도되지 않은 오동작이나 정상적인 처리 범위를 벗어난 불법적인 작업이 발생할 수 있다.
웹사이트의 유형이나 제공하는 기능에 따라서 파라미터 변조를 통해 발생할 수 있는 위협의 종류는 매우 다양하다. 일반적으로 발생 빈도가 높은 취약점 유형들을 정리하면 다음과 같다

  • 게시물 번호 조작을 통한 타 사용자의 게시물에 대한 무단 열람/수정/삭제
  • Role based 웹사이트에서 사용자 Role 등급의 임의 변경
  • 온라인 결재시 상품 금액 등 결재 데이터의 변조
  • 아이디, 사번 등의 변조를 통해 타 사용자 정보의 무단 열람 및 수정
  • 회원 가입시 실명 인증에 대한 우회
  • 접근이 제한되어 있는 정보에 대한 무단 열람 또는 변조
  • 인증 로직의 우회, 악성 파일의 업로드, 서버측 리소스에 대한 무단 다운로드

나. 보안 대책

파라미터 변수의 변조를 통한 공격을 방어하기 위해서는 Client 측에서 전송되어온 정보가 변조되었을 가능성이 있다는 것을 항상 고려하여 서버측 프로그램을 설계해야 한다. 예를 들면 GET/POST 변수, Cookie변수, HTTP Header, Referer 등 Client 에서 전송되어 온 대부분의 데이터가 변조될 수 있다.
따라서 이와 같은 데이터 변조에 대비하기 위해서는 웹사이트에서 인증, 결재, 정보의 열람 및 수정 등 중요한 작업을 설계할 때 다음과 같은 사항에 유의하여 신중하게 로직을 설계해야 한다.

  • 중요한 작업 수행시 Session 객체에 저장된 정보와 같이 Client 측에서 조작할 수 없는 신뢰할 수 있는 정보에 기반하여 적절한 권한을 가진 사용자에 의해 작업이 요청되었는 지를 반드시 검증해야 함
  • 여러 단계의 flow를 거쳐 수행되는 작업의 경우, flow의 시작과 끝 단계에서 작업에 사용된 변수들을 서로 비교 검증함으로서 중간 단계에서 특정 변수가 변조되지 않았는지 여부를 검사함 (예: 회 가입을 처리할 때 처음 단계에서 실명 인증이 통과된 성명/주민등록번호가 중간 단계를 거치는 동안 변조되었는지 여부를 마지막 저장 단계에서 검증해야 함)
  • 중요한 작업의 기준이 되는 정보 (예: 결재 모듈에서 상품의 가격 정보, 회원정보 수정시 사용자의 ID 정보 등)는 GET/POST 파라미터 등으로부터 입력 받은 변수값의 사용을 자제하고 Session 객체나 DB 와 같이 신뢰할 수 있는 저장소의 정보를 읽어와 사용하도록 함 (예를 들면 상품의 가격 정보는 DB에서 읽어오도록 하고, 사용자의 ID 는 Session 객체에서 읽어오도록 함)

이 유형의 취약점은 진단 대상의 구조 및 종류, 서비스 유형 등에 따라서 다양한 형태로 발생하게 되므로 각 진단대상의 특성과 로직을 분석하여 대상에 맞는 적절한 보안 대책을 적용해야 한다.

8. 취약한 ID/PW

가. 취약점 상세 내용 및 보안 대책

로그인 인증을 통과해야만 접근할 수 있는 웹페이지의 경우, 취약한 계정을 사용한다면, 공격자는 해당 웹사이트의 정보를 바탕으로 자주 사용되는 word를 이용한 사전 파일 공격을 시도하거나, 또는 무작위 대입 방식에 의해서 취약한 계정을 획득할 수 있음.
시스템에서 기본으로 제공하는 계정이나 DBMS, 어플리케이션 서버 등에서 관리를 위해 제공하는 기본 계정을 그대로 사용하는 경우 공격자에게 쉽게 계정의 사용 여부가 노출될 수 있음. 일반 사용자 계정 역시 여러 가지 방법으로 공격자에게 계정의 존재 여부가 노출될 수 있음.

나. 보안 대책

사용자가 취약한 패스워드를 사용할 수 없도록 패스워드 생성 규칙을 선정하고 이에 대한 안내 및 강제할 수 있는 로직을 적용해야 함.

  • 패스워드 생성 규칙 예시
    • admin, master 등 유추하기 쉬운 계정 이름 사용 금지
    • 8자 이상 숫자, 영문자, 특수문자를 혼합하여 패스워드를 생성해야 함
    • 자신과 관련된 정보를 이용한 패스워드 생성 금지(계정과 유사 한 패스워드 등)
    • 간단한 문자(영어단어 포함)나 숫자의 연속사용은 금함
    • 사전에 있는 단어, 이를 거꾸로 철자화한 단어 또는 숫자 하나를 더한 단어 사용 금지
    • 기억하기 쉽게 만들어 별도의 기록이 필요 없도록 함
    • 키보드상에서 일련화된 배열을 따르는 패스워드 선택 금지
    • 패스워드를 주기적으로 변경해야 함
    • 패스워드의 최소 사용기간, 최대 사용기간을 설정함
    • 이전에 사용한 패스워드는 재 사용 금지

9. 디렉터리 인덱싱

가. 취약점 상세 내용 및 보안 대책

웹서버 설정상의 오류나 개발 과정의 편의를 위해서 웹 디렉토리 내부의 파일 리스트가 웹브라우져를 통해서 출력되도록 설정되어 있을 수 있음
웹 디렉토리의 파일 목록이 노출되면 공격자에게 웹사이트 구조 및 환경과 관련된 정보가 노출될 수 있으며, 백업 파일이나 설정 파일 등이 웹 디렉토리 내부에 존재할 경우, 공격자가 이 파일을 다운로드하여 웹사이트의 핵심적인 정보를 획득할 수 있음

나. 보안 대책

사용중인 웹서버를 확인한 후, 설정 파일 또는 관리 콘솔상에서 Directory Indexing 을 허용하지 않는 것으로 변경함.

  • Apache
    DocumentRoot 디렉터리 내의 모든 파일의 목록이 출력되는 것을 방지하기 위해서 httpd.conf 파일 내의 <Directory> 설정 영역에서 “Options” 지시자 에서 “Indexes” 옵션을 제거한다.
    DocumentRoot 디렉토리의 최상위 디렉토리에서 Indexes 옵션을 제거하면 하위 디렉토리에도 모두 적용되지만 특정 하위 디렉토리에서 Indexes 옵션이 추가되어 있을 경우, 하위 디렉토리의 설정이 우선 적용되므로 하위 디렉토리의 모든 Indexes 옵션도 제거하도록 한다.
<Directory “/usr/local/www”>
    Options Indexes FollowSymLinks     (---> Indexes 지시어 삭제)
    AllowOverride None
</Directroy>
  • IIS
    인터넷 정보서비스(IIS) 관리 –> [해당 웹사이트] → [등록정보] → [홈 디렉토리] → [디렉토리 검색] 체크박스를 해제한다.

  • WebTob
    환경파일내의 ‘DIRINDEX’절 삽입유무 확인 후, ‘NODE’절의 ‘NODE’절에 ‘DIRINDEX’절과 관계된 설정을 확인한다. ‘DIRINDEX’절을 삽입하지 않거나 Options 값을 ‘-index’로 설정함
    (※ 환경파일 : ${WEBTOBDIR}/config/[파일명.m] )
*NODE
nex-edfa87d356c	WEBTOBDIR="C:/TmaxSoft/WebtoB4.1", 
		SHMKEY = 54000,
		DOCROOT="C:/TmaxSoft/WebtoB4.1/docs",
		PORT = "8080", 
		HTH = 1,
		LOGGING = "log1",
		ERRORLOG = "log2",
		JSVPORT = 9900,
		DirIndex = "diridx_full",
		Options = "-index"

*DIRINDEX
diridx_full	Options = "Fancy"

10. 디폴트 페이지

가. 취약점 상세 내용 및 보안 대책

웹서버, WAS 등 플랫폼을 디폴트 옵션으로 설치할 경우, 사용자의 편의를 위해 제공되는 각종 예제 및 샘플 페이지, 설치 정보, 관리 콘솔 등이 함께 설치된다. 이런 기능들은 제품별로 항상 동일한 경로에 설치되는 것이 일반적이며, 설치 정보가 일반에 공개되어 있기 때문에 공격자들의 주요 공격 목표가 될 수 있으며, 특히 샘플 페이지 등에 존재하는 취약점이 공격의 경로로 이용된 사례가 과거에 보고되어 있다.
따라서 샘플 페이지 등이 관리되지 않고 방치되는 경우 보안 취약점으로 작용할 가능성이 있는 만큼 사용하지 않는 기능은 설치하지 않거나 삭제하는 것이 바람직하며, 만일 사용되어야 하는 기능들은 철저한 관리를 통해 사고를 방지해야 한다.

나. 보안 대책

운영중인 웹서버에서 사용하고 있는 웹서버, WAS, Database, 기타 Third party 제품군을 파악하고 각 제품별로 디폴트로 설치되는 기능들 중에서 불필요한 기능이 있는지 검토하여 삭제하도록 한다.

  • 불필요한 샘플 페이지 및 기능의 삭제
    • 웹 서버/WAS의 Default Page와 Banner를 삭제
    • PHP의 phpinfo 페이지 삭제
    • WAS 등의 사용 예제 및 샘플 도메인 삭제
    • Tomcat, Jeus, IIS, Weblogic 등의 관리 콘솔 중 사용하지 않는 기능을 중지하거나 삭제
    • 기타 Third party 제품군의 관리 페이지, 샘플 페이지 등을 삭제
  • 디폴트 페이지 사용시 관리 강화
    • 디폴트 페이지나 관리 콘솔을 사용해야 하는 경우, 접근 경로 및 접근 port 의 디폴트 설정값을 변경하여 사용하도록 함
    • 관리 콘솔 설치시 생성되는 디폴트 계정은 사용하지 않도록 하고 별도의 계정을 생성하여 사용함
    • 관리 콘솔 등 중요한 기능의 경우 적절한 ACL 정책을 적용함
    • Third party 제품군의 관리 페이지 등이 일반에 노출되지 않도록 주의함