PHP 사용 가이드
이 문서는 안녕 리눅스에서 PHP를 사용할 때 알아 두어야 할 사항들을 정리한다.
안녕 리눅스의 PHP에는 여러가지 보안관련 addon 패치가 적용이 되어 있으며 다음과 같
다.
1. safe_mode_exec_dir patch
2. allow_include_extension patch
3. Image upload check patch
4. realpath_cache_force
등등..
이 외의 Default 값 변경 등의 요소들에 대해 설명을 한다.
현재, 안녕 리눅스 2 에서는 plus repository를 통하여 PHP 5.4와 5.5를 제공하고 있으
며, 별도의 언급이 없으면 모두 지원을 하는 것이다. (안녕 1.3의 PHP 5.2 포함)
1. ini 설정
안녕 리눅스의 php.ini는 다음의 위치에 있다.
/etc/php.d/php.ini (mod_php 설정)
/etc/php.d/php-cli.ini (php cli binary 설정)
/etc/php.d/php-fpm-cgi.ini (php-fpm package 설치시)
또한, 이 부속 설정으로
/etc/php.d/apache/*.ini
/etc/php.d/cli/*.ini
/etc/php.d/fpm/*.ini
에 extension 설정들이 있다.
기본적으로 php.ini의 설정들은 모두 overwrite 가 가능한 설정들이다. 그러므로 운
영상의 팁으로 보자면, 될수 있으면 /etc/php.d 에 있는 php.ini 나 php-cli.ini 는
건드리지 말고, /etc/php.d/{apache,cli.fpm}/Shared.ini에 필요한 설정을 추가하여
사용하는 것을 권장한다. 이렇게 운영을 할 경우, 기본 설정에서 무엇이 변경 되었
는지 여부를 쉽게 구분을 할 수 있으며, 인수인계에도 편리 하다.
참고로, 안녕 리눅스의 PHP package 는 소수의 extension 만 포함을 하고 있으므로,
php-exetnsion package를 추가해야 추가 확장을 사용할 수 있다.
2. short_tag OFF
안녕 리눅스의 PHP는 기본적으로 <? 로 PHP를 구동할 수 있는 short_tag 옵션을
php.ini에서 off 시켜 놓았다. 단순히 HTML 본문에서 <?=$var?> 사용하기 위하여
short_tag를 On으로 설정하는 경우가 있는데, 안녕에서 제공하는 5.3 부터는 이옵션
이 Off 이더라도, <?=$var?> 문법을 사용할 수 있도록 패치가 되어있다.
이 패치는 5.4 부터 지원하는 것을 5.3에 back porting 한 것이다.
참고:
. 안녕 1.x는 지원하지 않음
. 5.3의 경우 5.3.28-1 부터 지원
. 5.4 5.5는 기본 지원
3. allow_url_fopen / allow_url_include
이 옵션들은 보안상 injection이 발생할 수 있는 가장 취약점을 가지고 있는 옵션들
이다. 될 수 있으면, OFF 상태로 사용하는 것을 권장한다.
이 옵션들 중 allow_url_fopen의 경우, 코드상에서 PHP_INI_SYSTEM으로 설정되어 있
던 것을 PHP_INI_ALL로 패치가 되어 있다. (이는 ini_set으로 변경이 가능하다는 의
미이다.)
그러므로, fopen 등의 함수에서 외부 접근을 위하여 ini file에서 전역으로 On 으로
설정하지말고, 필요한 페이지에서만 ini_set 으로 On 설정을 해서 사용하는 것을 권
장한다.
이 설정을 ini_set 으로 설정하는 것은 해당 페이지 전역으로 영향을 미친다.
다음의 코드에서,
Hanterm - cat sample.php |
<?php
$page = 'https://domain.com/abc/';
$fp = fopen ($page, 'rb');
ini_set ('allow_url_fopen', true);
?>
|
allow_url_fopen 이 fopen 보다 후에 호출이 되었지만, 실제로 ini_set 이전에 호출
된 fopen에서 allow_url_fopen 에서 적용이 됨을 확인할 수 있다.
4. alias function 제공
안녕 리눅스의 PHP에서는 기본적으로 다음의 함수들은 disable_functions 에 등록이
되어 있다.
phpinfo
php_uname
sys_get_temp_dir
phpversion
ini_get
ini_get_all
ini_set
get_cfg_var
assert
이 함수들은 php shell에서 OS 확인을 위해 주로 사용을 하는 함수들로서 이 함수들
을 사용하지 못하게 했을 경우, php shell의 동작을 무력화 시킬 수 있다.
대신에, disable된 함수들의 앞에 '___' (under-bar 3개)블 붙이면 사용을 할 수 있
도록 alias function을 제공한다.
___phpinfo
___php_uname
___sys_get_temp_dir
___phpversion
___ini_get
___ini_get_all
___ini_set
___get_cfg_var
___assert
이 패치가 안된 PHP와의 호환성을 위하여, /usr/share/php/AliasFunc.php 파일을 제
공하며, 이 파일을 php.ini의 auto_prepend_file 에 등록을 해 주면, 안녕의 PHP 와
동일하게 사용을 할 수 있다. 또는 code에서 이 파일을 include 해 주면된다. 이 파
일은 php-pear package에 포함이 되어 있다.
참고:
. PHP 5.2(안녕 1.x 용) 에서는 __assert는 지원하지 않는다.
5. allow_include_extension Patch
php.ini에 allow_include_extension 설정을 추가한다. 기본값은 .php 이다.
안녕 리눅스의 PHP 는 include 시에 injection 을 방지하기 위하여 기본적으로 .php
확장자만 include 할 수 있게 되어 있다. php.ini의 allow_include_extension 에 등
록되지 않은 확장자를 include/require 할 경우, 다음과 같은 에러 메시지가 출력된
다.
Hanterm - php ./test.php |
shell> cat test.php
<?php
include 'top.html';
?>
shell> php ./test.php
Fatal error: include(): Failed opening 'top.html' for security
issues in ./test.php on line 2
shell>
|
여기서 주의해야 할 것은, .html 확장자에서 php 를 구동 할 수 있도록 설정을 했을
경우 allow_include_extension에 .html이 등록되지 않으면 .html 을 php 가 구동 할
때 동일한 에러가 발생한다. 이는 php 가 특정 파일을 구동 할 때, include/require
루틴을 이용하여 구동할 파일을 open하기 때문에 발생을 한다.
이 패치가 필요한 이유는 다음과 같다.
Hanterm - cat sample.php |
<?php
include "$table";
blah blah~
?>
|
cracker등이 게시판 업로드 등의 기능을 이용하여, jpeg file header 에 PHP 코드를
삽입한 다음, 위의 코드처럼 include에 injection 가능한 코드가 있을 경우, $table
변수에 해당 jpeg file을 include 하게 하여 의도하지 않은 php를 구동 할 수 있다.
이런 경우를 원천적으로 차단하기 위하여 include/require 를 할 수 있는 확장자를
php 구동이 가능한 파일로 한정을 하는 것이다.
또한, allow_include_extension 옵션은 file upload 시에 이 옵션에 설정된 확장자를
업로드 할 경우 $_FILES['userfile']['error'] 를 UPLOAD_ERROR_ILLEGAL 상수로 반환
하고 upload를 취소 시키다.
$_FILES['userfile']['error'] 의 값이 UPLOAD_ERROR_ILLEGAL 일 경우, error loggin
이 되며, E_WARNING을 발생 시킨다. 이 값일 경우에는 즉시 수행을 중지 시키는 것이
좋다.
Hanterm - cat sample.php |
<?php
if ( $_FILES['userfile']['error'] == UPLOAD_ERROR_ILLEGAL ) {
throw new Exception ($_FILES['userfile']['secstr'], E_USER_ERROR);
}
?>
|
6. safe_mode_exec_dir Patch
이 패치는 Safe mode가 아니더라도 php.ini 의 safe_mode_exec_dir 사용을 가능하게
한다. 기본값은 /var/lib/php/bin 이다.
safe_mode_exec_dir =
와 같이 빈값을 주었을 경우, original PHP 처럼 아무 제약없이 사용할 수 있다. 만
약 설정 자체가 안되어 있다면(해당 옵션이 주석처리 되어 있다면) 기본값이 적용이
된다. 안녕 리눅스의 기본 값은 /var/lib/php/bin 이다.
예를 들어 safe_mode_exec_dir 값을 /some/bin 으로 지정한다면 다음의 코드는
Hanterm - cat sample.php |
<?php
system ('cat $(echo "/etc/passwd") | /bin/grep root; ls -al');
?>
|
아래와 같이 변경 되어 실행이 되게 된다.
Hanterm - cat sample.php |
/some/bin/cat $(/some/bin/echo "/etc/passwd") | /some/bin/grep root; /some/bin/ls -al'
|
즉 모든 명령어의 경로를 무시하고 safe_mode_exec_dir 에 지정된 경로에서 해당 명
령을 실행한다는 의미이다.
Safe Mode 시의 동작과의 차이는 위의 예제에서 보이듯이 Safe mode 시에는 null 문
자나 Meta 문자 이후를 모두 제거 시킨 후에 명령어의 경로를 변경 시키는 반면, 이
패치는 Same mode 가 아닐 경우, system 명령을 사용할 수 있는 대부분의 case를 지
원을 한다.
지원하는 파서는 다음과 같다.
명령; 명령
명령 $(명령)
명령 $(명령 $(명령))
명령 $(명령 `명령`)
명령 `명령`
명령 | 명령
명령 && 명령
명령 || 명령
php 5.4 부터는 Safe Mode가 제거가 되었기 때문에 exec_dir 옵션으로 제공이 된다.
7. Image upload check Patch
안녕 리눅스의 PHP 는 PHP upload 시에 image file 의 경우 image header 에 PHP 코
드가 삽입이 되어 있는지 여부를 검사 할 수 있다.
php.ini 에서 다음의 설정들을 참고 하도록 한다. 다음 값들은 기본 설정 값들이다.
upload_image_check = On
이미지 파일 헤더에 <? 문자가 존재하면 <? 부터 16byte의 데이터에 PHP 코드
가 있는지 여부를 검사한다. 검사 로직은 다음과 같다.
1. 헤더에 <?php 또는 <= 문자가 있으면 에러 처리를 한다.
2. <? 다음에 ASCII 문자가 있을 경우 white list 에 등록되어 있지 않은 패턴
에 대해서 에러 처리를 한다.
2번의 경우 short_tag를 지원할 경우 때문에 체크를 할 수 밖에 없다. 이 경우 이미
지 edit tool (Photo shop 또는 gimp 등)에서 프로그램 header를 XML로 넣는 경우가
많은데, 이 경우 충돌을 할 수 있으므로 pattern white list 를 잘 관리 해야 한다.
이 패치는 XML tag 때문에 오탐의 여지가 있다. 그러므로 image file의 경우에는 업
로드 전에 될 수 있으면 header 를 제거한 채 업로드 하는 것을 권장한다. (이는 보
안상의 이슈도 있지만, 이미지 용량상의 문제도 있다.)
upload_image_check_log = On
이미지 파일에 PHP code 가 탐지가 되면 php_log_err API 로 logging 을 한다.
upload_image_check_test = On
On 으로 설정이 되면 PHP code 가 탐지가 되더라도 logging 만 한다. Off 일 경우에
는 E_WARNING 처리와 함께 에러 코드 UPLOAD_ERR_SECURITY 로 처리한다.
upload_image_check_whitelist =
white list로 지정할 패턴을 기록한 파일의 경로를 지정한다. white list는 new line
을 구분자로 지정할 수 있으며 pattern 하나당 최대 16자를 넘으면 안된다.
이 패치는 오탐이 있기 때문에 코드를 중지 시키는 방향으로 사용하는 것은 권장하지
않는다. 그러므로, upload_image_check_test 를 On으로 설정하고 코드에서 Notice 등
의 action을 추가 하도록 하는 것을 권장한다.
Hanterm - cat sample.php |
<?php
if ( $_FILES['userfile']['error'] == UPLOAD_ERROR_SECURITY ) {
$to = 'sec@company.com';
$subj = sprintf (
'Security Issue: image upload (%s)',
$_FILES['userfile']['name']
);
$msg = $_FILES['userfile']['secstr'];
$headers = 'From: sec_code@' . $_SERVER['hostname'] . "\r\n";
mail ($to, $subj, $msg, $headers);
}
?>
|
8. realpath_cache_force Patch
2006년 경, Stefan Esser 라는 보안 컨설턴트가 PHP 의 보안 문제로 PHP 개발자들과
다투고 나서, PHP 보안 버그에 대해서 무차별 공개를 하였고, 그 보안 버그 중 한가
지 문제로 인하여 5.1 부터 open_basedir이 설정될 경우, realpath_cache 를 사용하
지 못하도록 수정이 되었다.
이 문제는 link 함수로 race coudition을 수행하여 relapath_cache를 open_basedir
제약을 받는 것처럼 속여 제약을 풀어 버리는 문제이다.
이 문제 해결을 위하여 PHP 개발자들은 open_basedir 이 설정되었을 경우 realpath
cache를 하지 않도록 수정을 하여, open_basedir 사용 시에 CPU 부하를 증가 시키는
문제가 발생하고 있다. ('openbse_dir realpath_cache' 로 검색하면 이 문제에 대한
글들을 쉽게 찾아볼 수 있다.
안녕 리눅스의 PHP는 이 문제를 해결하기 위하여 php.ini에서 realpath_cache_force
라는 옵션을 제공하며, 이 옵션을 enable 하면 symlink 함수와 link 함수를 사용하지
못하게 하는 대신 realpath caching 을 사용할 수 있도록 지원한다.
realpath_cache_force = On
참고:
. 안녕 1.3은 지원하지 않음
. 5.3은 5.3.18-2 이후 버전 부터 지원
. 5.3과 5.4에서는 보안상 symlink 함수와 link 함수를 disable_functions 에 등
록 할것 (race condition을 이용한 open_basedir 무력화 가능함)
. 5.5(plus repository)에서는 realpath_cache_force를 On하면 자동으로 symlink
함수와 link 함수를 사용하지 못하도록 막음
|