CGI 오류: Premature end of script headers (Internal Server Error)

by ADMINPLAY posted Dec 14, 2008
?

단축키

Prev이전 문서

Next다음 문서

ESC닫기

크게 작게 위로 아래로 댓글로 가기 인쇄
웹호스팅 서버에서 cgi를 사용하려고 /cgi-bin/ 폴더에 cgi 파일을 올려놓고(또는 직접 vi로 작성하여) 실행권한을 주고(chmod 755) 웹브라우저에서 열어보면 "Internal Server Error" 문구가 뜨는 경우가 종종 있습니다.

httpd.conf 파일을 열어 CGI가 실행되게끔

AddHandler cgi-script .cgi .pl
AddType application/x-httpd-cgi .cgi
AddType application/x-httpd-cgi .pl
의 주석(#)도 제거해보고, 추가로 AddType도 넣고, Directory 옵션에
<Directory...>
  ...
  Options ExecCGI
  ...
</Directory>
ExecCGI 를 넣어 CGI의 실행을 허용해보기도 하지만
웹브라우저에서는 계속 "Internal Server Error" 메세지만 나와 상세한 오류 내용을 보려고 error_log 파일을 열어보면

# tail -f ./error_log
...(생략)...
[error] [client xx.xx.xx.xx] Premature end of script headers: test.cgi
라고 나옵니다.

이런경우 보안상 아파치에서 suEXEC를 실행하여 CGI의 가상 웹서버에서의 cgi 실행을 막고있음을 의심해 보아야 합니다.



어떻게 suEXEC 가 실행중인지 알수있나...

아파치의 error_log 파일을 열어보아 내용중에 다음과 같은 문구가 있는지 확인합니다.
[notice] suEXEC mechanism enabled (wrapper: /usr/sbin/suexec)
위 라인은 아파치가 매번 시작할때 표시 됩니다.(경로는 시스템에 따라 다를 수 있음)

그럼 suEXEC 의 위치는 어떻게 찾을까요?  아래와 같이 해보세요.
# cd /usr/sbin
# ./httpd -V | grep SUEXEC_BIN
 -D SUEXEC_BIN="/usr/sbin/suexec"

위의 파란글씨로 된 부분이 suEXEC 의 위치입니다.



도대체 suEXEC 가 하는 일은 뭔가?

여러분이 httpd.conf 를 위와 같이 설정하여 CGI 사용을 허가 하였다면 서버는 사용자가 만든 cgi 프로그램을 다음와 같은 두가지 옵션을 통해 실행하게 됩니다.

1. suEXEC 없이 실행
   웹서버 사용자 자격으로 CGI 프로그램을 실행.
   이것은 사용자가 웹서버가 할 수 있는 어떤일도 할 수 있는 프로그램을 만들수 있단 이야기.(보안상 취약)

2. suEXEC 를 통한 제어
   이 경우 호스팅 서비스 사용자의 계정으로 CGI 프로그램을 실행함으로 미리 설정된 호스팅 사용자의 자격 여건에 지배를 받게됩니다. 그렇지 않을 경우 suEXEC는 프로그램을 실행하지 않습니다.

   suEXEC의 올바를 권한 설정은 아래와 같습니다:
# chown root suexec
# chgrp root suexec
# chmod 4711 suexec

대개의 경우 suEXEC를 지우거나 이름을 변경하고 아파치를 재실행하면 문제가 되었던 "Internal Server Error" 는 사라지게 됩니다.
# cd /usr/sbin
# mv suexec suexec.disabled
# service httpd restart
※ 해당 디렉토리에서 suEXEC 가 발견되지 않으면 아파치는 suEXEC를 실행하지 않고 서비스를 시작합니다.

이제 문제가 되었던 cgi 페이지를 웹브라우저에서 열어봅니다.
이와 같이 suEXEC를 실행하지 않음으로 문제를 해결하였습니다.


만일 suEXEC를 실행한 상태에서 사용가 계층에서의 cgi 실행 권한을 가상 호스트 환경에서 주고자 한다면 계속해서 아래 펌글을 참조하세욘.

******************************************************
보통 cgi는 보안상 굉장히 취약한 점이 많아 서비스 하기를 꺼려하기 마련이지만 그렇다고 범용적으로 사용하는 cgi를 막아놓으면 일반 사용자들의 불편함과 항의를 감수해야 하므로 보안대책이 필요합니다.

그중 많이 사용하는 것이 cgiwrap과 아파치 자체 suexec 입니다. cgiwrap 같은경우 보다 유연한 설정과 범용성을 가지고 있으나 suexec 보다 보안기능이 강력하다고 볼 수는 없기에 필자는 주로 suexec를 사용합니다.

suexec 는 Apache 1.3.x 와 2.x.x 모두 지원합니다. 다만 mod_suexec 의 경우 2.x.x 에서만 지원하므로 참고 바랍니다.

자세한 내용은 apache 1.3.x 의 경우 "Apache suEXEC Support" 를 참고 하시고, 2.x.x 의 경우 "suEXEC 지원" 을 참고 하시기 바랍니다.

저는 apache 1.3.29 에서 설치 하였으니 이 버전을 가지고 설명을 하도록 하겠습니다. 2.x.x에서도 설치는 거의 비슷하나 httpd.conf 설정이 약간 달라지니 관련 문서를 참고하세요.

일단 아파치 설치시 configure 설정은 다음과 같이 하였습니다.

./configure
--prefix=/usr/local/apache
--enable-shared=max
--enable-rule=SHARED_CORE
--enable-module=so
--enable-suexec // 이 부분부터 suexec와 관련된 설정입니다.
--suexec-caller=nobody // 기본 웹사용자를 말합니다.
--suexec-docroot=/home // 루트 문서 디렉토리로 자세한 설명은 아래 참고 하세요.
--suexec-userdir=public_html // 일반 유저 디렉토리를 말합니다.
--suexec-uidmin=500 // 최소 UID 입니다. 즉, UID가 500 미만일 경우 cgi가 실행되지 않습니다.
--suexec-gidmin=500 // 최소 GID 입니다. 즉, GID가 500미만일 경우 cgi가 실행되지 않습니다.
--suexec-safepath=/usr/local/bin:/usr/bin:/bin // cgi에서 호출 가능한 실행파일이 위치한 경로

제가 suexec 를 사용해본 결과 조금만 설정이 잘못되도 각종 에러와 함께 작동이 되지 않았습니다. 특히나 가상호스트(VirtualHost)를 사용한다면 기본설정 디렉토리 즉, 저의 경우 /usr/local/apache/htdocs 로 했을경우에는 각 사용자의 디렉토리의 cgi가 실행 안되는 현상이 발생했습니다. 물론 가상호스트가 아닌 ~Username/xxx.cgi 형식의 cgi들은 제대로 잘 돌아갔습니다만 VirtualHost 를 사용하면 docroot 하위 디렉토리 이외의 곳에서는 에러가 발생하더군요. 얼마간의 삽질모드(?) 끝에 docroot를 위와 같이 /home 으로 해주면 된다는 것을 알게 되었습니다. 메뉴얼에 보면 userdir 을 이런식으로 하라고 나와있는데 저의 경우 맞지 않더군요.

아무튼 이상과 같이 설치 해서 make; make install 하면 아파치 설치가 되며, 기본적으로 /usr/local/apache/bin/suexec 라는 파일이 생성됩니다. suexec -V 옵션을 주면 제대로 설치가 됐는지 알 수가 있습니다. 또는 httpd -l 해보시면 마지막 줄에 suexec : enabled 라고 나오면 정상적으로 작동되는 것입니다.

[root@lux sh]# /usr/local/apache/bin/suexec -V
-D DOC_ROOT="/home"
-D GID_MIN=500
-D HTTPD_USER="nobody"
-D LOG_EXEC="/usr/local/apache/logs/suexec_log"
-D SAFE_PATH="/usr/local/bin:/usr/bin:/bin"
-D UID_MIN=500
-D USERDIR_SUFFIX="public_html"


[root@lux sh]# /usr/local/apache/bin/httpd -l
Compiled-in modules:
  http_core.c
  mod_so.c
suexec: enabled; valid wrapper /usr/local/apache/bin/suexec

설치가 됐다면 잘되는지 테스를 해봐야겠죠.
일단 httpd.conf 파일에서 VirtualHost 부분에 suexec 에서 사용할 user와 group을 지정합니다. 이때 애초에 suexec-uidmin과 suexec-gidmin에 지정된 숫자보다 높은 uid와 gid 를 가진 사용자와 그룹만 지정할 수 있습니다.
아파치를 재가동한뒤에 로그파일을 보면 suexec가 정상적으로 돌아가는지 알 수 있습니다.  error_log 파일에 suEXEC mechanism enabled (wrapper: /usr/local/apache/bin/suexec) 이런 메시지가 나오면 suexec가 작동되는 것입니다.

이제 실제로 cgi 예제를 만들어서 테스트 해보도록 하겠습니다. 테스트를 위해 일반 사용자 디렉토리의 Options 를 ExecCGI로 조정했습니다. 그리고 가상 호스트는 아래와 같이 세팅하였습니다.

<VirtualHost *:80>
User nice
Group nice
ServerAdmin niceXXXX@gmail.com
DocumentRoot /home/nice/public_html
ServerName nice2seeyou.com
ErrorLog logs/nice2seeyou.com-error_log
CustomLog logs/nice2seeyou.com-access_log common
</VirtualHost>

shell> vi test.cgi

#!/bin/sh
echo "Content-type:text/html"
echo
echo
exec mkdir test_dir


파일을 만들었으면 권한을 700으로 자신(nice)만 실행되게끔 해놓고 웹에서 test.cgi를 불러와 보세요. 그럼 해당 디렉토리에 test_dir 이라는 디렉토리가 생성될 것입니다. 예제에서 보다시피 일반적인 cgi 권한은 nobody (혹은 apache) 이지만 suexec를 사용하면 일반 사용자 권한으로 보다 안전한 방법으로 cgi를 실행 할 수 있습니다. 저는 보안기능도 그렇지만 이점에 더욱 매력을 느껴서 suexec를 애용합니다.

잘 이용하면 웹에서 /etc/passwd를 이용한 인증이나 passwd 명령등을 통해 계정의 비밀번호등을 변경등을 할 수도 있습니다. 이밖에 활용용도가 많겠죠^^