PHP 안전 모드(safe mode)는 공유-서버 보안 문제를 풀려는 시도이다.
이 문제를 PHP 수준에서 풀려고 하는것은 구조적으로 올바르지 않다.
그러나 웹서버와 OS 수준에서의 차선책이 아주 현실적이지는 않기 때문에,
많은 사람, 특히 ISP, 들이 현재 안전 모드를 사용한다.
보안과 안전 모드
표 22-1. 보안과 안전 모드 설정 지시자(directive)
| 지시자명 | 기본값 | 변경값 |
|---|
| safe_mode | "0" | PHP_INI_SYSTEM |
| safe_mode_gid | "0" | PHP_INI_SYSTEM |
| safe_mode_include_dir | NULL | PHP_INI_SYSTEM |
| safe_mode_exec_dir | "" | PHP_INI_SYSTEM |
| safe_mode_allowed_env_vars | PHP_ | PHP_INI_SYSTEM |
| safe_mode_protected_env_vars | LD_LIBRARY_PATH | PHP_INI_SYSTEM |
| open_basedir | NULL | PHP_INI_SYSTEM |
| disable_functions | "" | PHP_INI_SYSTEM |
| disable_classes | "" | PHP_INI_SYSTEM |
PHP_INI_* 상수에 대한 좀 더 자세한 설명과 정의를 보기 위해서는
ini_set() 참조.
위 설정 지시어에 대한
간단한 설명입니다.
- safe_mode
boolean
PHP의 안전 모드가 활성화되어있는지 여부.
더 자세한 정보는 보안장을 참고.
- safe_mode_gid
boolean
기본값, 안전 모드는 파일이 열릴 때 UID 비교 검사를 수행한다.
이 설정을 GID 비교로 완화하려면, safe_mode_gid을 켜도록 한다.
파일 접근에 대해 UID (FALSE) 검사를 하는지,
GID (TRUE) 검사를 하는지의 여부.
- safe_mode_include_dir
string
이 디렉토리와 하위디렉토리에서 파일을 include할 때에는
UID/GID 검사가 무시된다
(디렉토리는 include_path나 include되는
전체 경로가 되어야 한다).
PHP 4.2.0부터 이 지시자(directive)는 단지 하나의 디렉토리보다는
include_path 지시자와 비슷한
방식으로 세미-콜른으로 구분된 경로를 취할수 있다.
설정 제한은 실질적으로 디렉토리명이 아닌 앞첨자(prefix)가 된다.
이말의 의미는 "safe_mode_include_dir = /dir/incl"는
"/dir/include"와 "/dir/incls"가 존재하기만 한다면 그 디렉토리도 접근이 허용된
다는 것이다. 특정 디렉토리만으로 접근을 제한하고자 하면, 슬래시로 끝내면 된다.
For example: "safe_mode_include_dir = /dir/incl/"
- safe_mode_exec_dir
string
PHP가 안전 모드를 사용중이라면, system()과 그 외의
시스템 프로그램을 실행하는 함수는
이 디렉토리에 있지 않으면 프로그램 시작이 거부된다.
- safe_mode_allowed_env_vars
string
특정 환경 변수를 설정하는것은 잠재적인 보안 구멍이 될수 있다.
이 지시자는 콤마-구분자 리스트의 앞첨자(prefix)를 포함한다. 안전 모드에서,
유저는 여기서 제공되는 앞첨자로 시작하는 이름을 갖는 환경변수만 변경할수
있을것이다. 기본값으로, 유저는 PHP_로 시작하는 환경 변수만 설정할수 있다.
(e.g. PHP_FOO=BAR).
참고:
이 지시자가 비어있으면, PHP는 유저가 모든 환경 변수를 변경할수 없게 할것이다!
- safe_mode_protected_env_vars
string
이 지시자는 엔드 유저가 putenv()를 사용하여 변경할수 없는
콤마-구분자 리스트의 환경 변수를 포함한다. 이 변수들은
safe_mode_allowed_env_vars가 그들을 변경할수 있도록 설정되어있을지라도
보호될것이다.
- open_basedir
string
PHP가 열수 있는 파일을 특정 디렉토리-트리로 제한한다.
이 지시자는 안전 모드가 켜졌는지 꺼졌는지와는 상관이 없다.
스크립트가 예를 들면, fopen() 이나
gzopen()으로 파일을 열려고 시도할때, 파일의 위치를 검사한다.
파일이 설정된 디렉토리-트리의 밖에 있다면, PHP는 그 파일을 여는것을 거부할것이다.
모든 심볼릭 링크가 검사되기 때문에, symlink로 이 제한을 회피할수 없다.
특수한 값 .는 스크립트가 저장되어 있는
디렉토리를 기본-디렉토리(base-directory)로 사용한다는 것을 가리킨다.
윈도우에서는 세미콜른으로 디렉토리를 구분한다. 그외 모든 시스템은,
콜른으로 디렉토리를 구분한다. 아파치 모듈에서, 부모 디렉토리부터의
open_basedir 경로는 현재 자동적으로 상속된다.
open_basedir로 설정된 제한은 실질적으로 디렉토리명이 아닌, 앞첨자(prefix)가
된다. 이 말의 의미는 "open_basedir = /dir/incl"는 "/dir/include" 과
"/dir/incls" 디렉토리가 존재한다면 그 두 디렉토리로의 접근도 허용한다는것이다.
특정 디렉토리로만 접근을 제한하고자 한다면, 슬래쉬로 끝내면 된다.
For example: "open_basedir = /dir/incl/"
참고:
다중 디렉토리에 대한 지원은 3.0.7에서 추가되었다.
기본값은 모든 파일이 열릴수 있도록 허용되어 있다.
- disable_functions
string
이 지시자는 보안 때문에
특정 함수를 비활성화시켜준다. 컴마로 구분된 함수명의 리스트를 취한다.
disable_functions는 안전 모드에
의해 영향을 받지 않는다.
이 지시자는 php.ini에서 설정되어야 한다. 예를 들면,
이 값을 httpd.conf에서 설정할수 없다.
- disable_classes
string
이 지시자는 보안적인 측면때문에
특정 클래스를 비활성화시켜준다. 컴마로 구분된 클래스명의 리스트를 취한다.
disable_classes는 안전 모드에
의해 영향을 받지 않는다.
이 지시자는 php.ini에서 설정되어야 한다. 예를 들면,
이 값을 httpd.conf에서 설정할수 없다.
Availability note:
이 지시자는 PHP 4.3.2부터 사용가능하게 되었다.
참고: register_globals,
display_errors,
log_errors
safe_mode가 켜져 있으면, PHP는 현재 스크립트의
소유자(owner)가 파일 함수에 의해 제어되는 파일의 소유자(owner)와 일치하는지 검사한다.
예를 들면:
-rw-rw-r-- 1 rasmus rasmus 33 Jul 1 19:20 script.php
-rw-r--r-- 1 root root 1116 May 26 18:01 /etc/passwd |
이 script.php를 실행
<?php readfile('/etc/passwd'); ?>
|
안전 모드가 활성화되어 있으면 다음 에러가 보여진다.
Warning: SAFE MODE Restriction in effect. The script whose uid is 500 is not
allowed to access /etc/passwd owned by uid 0 in /docroot/script.php on line 2 |
엄격한 UID 검사가 적절하지 않고,
완화된 GID 검사가 효율적인 환경일수 있다.
이런 경우는 safe_mode_gid 스위치 방식으로
지원된다. On으로 설정하면 완화된 GID 검사가
수행되고, Off (기본값)로 설정되면 UID 검사가
수행된다.
safe_mode 대신에,
open_basedir 디렉토리를 설정하면,
모든 파일 제어가 특정 디렉토리 밑의 파일로만 제한될것이다.
예를 들면(아파치 httpd.conf 예):
<Directory /docroot>
php_admin_value open_basedir /docroot
</Directory> |
이
open_basedir 설정으로
동일한 script.php를 실행하면 결과는 다음과 같다:
Warning: open_basedir restriction in effect. File is in wrong directory in
/docroot/script.php on line 2 |
또한 각각의 함수들을 비활성화시킬수 있다.
disable_functions 지시자는
php.ini 파일 밖에서 사용될수 없다. 그래서 httpd.conf 파일의 per-virtualhost 나
per-directory 기반의 함수를 비활성화시킬수 없다.
이 지시자를 php.ini에 추가하면:
disable_functions readfile,system |
다음의 결과가 나온다:
Warning: readfile() has been disabled for security reasons in
/docroot/script.php on line 2 |