문서의 이전 판입니다!


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) 특정 페이지에 인증 및 권한 관리 모듈이 누락된 경우

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

  • 이 페이지는 접근시 인증이 필요한 페이지 인가?
  • 이 페이지에 접근하는 모든 유저에 대해서 인증 및 권한이 적절하게 검사되고 있는가?