아파치웹서버보안 #5 : 아파치 보안모듈 mod_security 설정
작성자 정보
- 관리자 작성
- 작성일
컨텐츠 정보
- 5,948 조회
- 0 추천
- 목록
본문
mod_security 설정
위와 같이 모듈을 포함하여 설치하였다고 해서 바로 기능을 사용할 수 있는 것은 아니다. 설정파일에서 기능을 사용할 수 있도록 별도의 설정을 해 주어야 하기 때문이다.
. mod_security는 많은 지시자를 이용하여 관리자가 원하는 기능을 설정하거나 제어할 수 있도록 제공하고 있는데, 직접 적용하여 사용할 수 있도록 아래 URL에서 1.9.x의 설정 예를 제공하고 있다.
.
http://www.modsecurity.org/documentation/quick-examples.html
위의 예를 참고로 설정 파일인 httpd.conf에 직접 설정해 보도록 하자.
mod_security 설정 부분은 아래와 같이 <IfModule mod_security.c>와 </IfModule> 사이에 지정하면 된다.
modsecurity 2.x 룰에 대해서는 잠시 후에 살펴보도록 하겠다.
<IfModule mod_security.c> SecFilterEngine On SecFilterScanPOST On SecFilterDefaultAction "deny,log,status:404" SecFilterCheckURLEncoding On SecFilterForceByteRange 32 126 ......... ...중략... </IfModule> |
위의 설정 지시자들에 대한 설명은 다음과 같다.
SecFilterEngine On |
mod_security의 필터링 기능을 사용할 것인지 여부를 정의하는 것이다.
. On은 모든 요청에 대해 분석하고, Off는 분석하지 않는다.
SecFilterScanPOST On |
POST 메소드로 전달되는 payload를 체크 할 것인지 여부를 지정한다.
참고로 GET 메소드는 변수=값&변수=값&...의 형식으로, Request Header의 HTTP resource ID를 지정하는 곳에 CGI 프로그램 이름과 함께 연이어 데이터를 전달하는 방식이며 POST 메소드는 Resouce ID 필드에 CGI 프로그램 이름만 주고 데이터는 message body 부분에 전달하는 방식이다.
.
SecFilterDefaultAction "deny,log,status:404" |
필터에 매칭 되는 요청이 있을 때 어떻게 대응할 것인지에 대한 기본 설정으로 위와 같이 설정하면 필터에 매칭 되었을 경우 요청을 차단 후 404 에러를 넘겨주고 로그를 남기게 된다.
여기에서 제공되는 action에는 다음과 같은 것들이 있다.
.
pass : 필터링하지 않고 통과하도록 한다.
예)SecFilter KEYWORD "pass,log"
deny : 필터링에 매칭 될 경우 요청을 거부한다.
특별한 status를 지정하지 않으면
기본적으로 500 error로 응답한다.
status : 요청이 거부되었을 경우 제공되는 HTTP 상태 코드를 지정한다.
예)SecFilter KEYWORD "status:404"
redirect : 필터링에 매칭 될 경우 특정 URL로 redirect할 수 있다.
.
예)SecFilter KEYWORD "redirect:http://www.police.go.kr"
exec : 필터링에 매칭 될 경우 지정한 명령어 또는 cgi를 실행하도록 한다.
예) SecFilter KEYWORD "exec:/home/report/report-attack.pl"
log : 필터링에 매칭 될 경우 apache의 에러 로그에 남기도록 한다.
nolog : 에러 로그에 남기지 않도록 한다.
pause : 요청에 응답하기 전에 지정된 밀리 초 동안 멈추도록 한다.
이는 웹스캐너 등을
교란시킬 때 사용될 수 있는데, 잘못 사용되면 서비스거부가 될 수도 있으니
주의하여야 한다.
따라서 초기에 탐지모드로만 운영하려면 SecFilterDefaultAction "pass,log" 로 설정하여 사용하면 된다.
탐지모드로 차단하지 않고 로그만 남도록 설정했는데도 차단되는 경우가 있다.
. 이는 SecFilterSignatureAction "msg:'Command execution attack'" SecFilterSelective ARGS_VALUES ";[[:space:]]*(pwd|wget|curl)“ .......와 같이 설정 시 발생하는데 이는 하단의 룰이 매칭 시 SecFilterSignatureAction에서 지정한 msg가 일괄적으로 남도록 하는 것인데, SecFilterSignatureAction의 기본값이 룰에 매칭 시 차단하도록 하는 log,deny,status:403이기 때문이다.
. 따라서 이러한 경우 SecFilterSignatureAction을 사용하지 않거나 SecFilterSignatureAction "log,pass,msg: 'Command execution attack ''와 같이 변경하여 사용하면 된다.
|
SecFilterCheckURLEncoding On |
URL로 전달되기 전에 특수문자는 encoding될 필요가 있는데, encoding된 문자가 유효한지를 체크할지 여부를 지정한다.
SecFilterForceByteRange 32 126 |
Stack Overflow 공격을 차단하기 위해 Request의 byte를 제한할 수 있다.
. 기본적으로는 제한이 없지만 위와 같이 설정 시 32byte부터 126byte만 허용한다.
SecFilterDebugLog logs/modsec_debug_log SecFilterDebugLevel 0 |
요청이 들어올 때 log를 남길 것인지 설정한다.
0은 남기지 않는 것이고, 1은 심각한 이벤트가 발생하였을 때, 2, 3으로 갈수록 자세한 정보를 남기게 된다.
정상적으로 로그는 남길 필요가 없으므로 여기에서는 남기지 않도록 0으로 설정한다.
SecFilter KEYWORD |
mod_security의 핵심 기능으로서 서버로 들어오는 요청에 대해 특정한 문자열을 포함할 경우 필터링하도록 하는 것이다.
. GET일 경우 요청의 첫줄만 체크하며 SecFilterScanPOST on으로 설정하였을 경우 POST는 메시지 부분도 체크하게 된다.
만약 SecFilter /bin/sh와 같이 지정하면 웹을 통해 쉘 명령어를 실행하려는 시도를 필터링하게 되는데, 이와 같이 경로를 지정할 경우 /bin/.sh와 같이 IDS등의 필터를 속이기 위한 시도도 탐지하여 필터링할 수 있다.
. 아울러 keyword에는 단순 문자열뿐만 아니라 정규식도 사용가능하며 SecFilter "!php"와 같이 !로 시작하면 이후의 문자열을 포함하지 않는 모든 요청을 필터링 할 수도 있다.
. 또한 각각의 필터링 규칙에 옵션으로 action을 지정할 수도 있다.
.
SecFilterSelective LOCATION KEYWORD [ACTIONS] |
SecFilter가 단순한 매칭을 제공한다면 SecFilterSelective는 심화된 매칭 기능을 제공한다.
이를테면 아래와 같은 경우 클라이언트의 ip나 호스트에 특정 문자열이 있을 경우 매칭 되는 것이다.
.
SecFilterSelective "REMOTE_ADDR|REMOTE_HOST" KEYWORD |
LOCATION에는 REMOTE_USER, REQUEST_METHOD, REQUEST_URI등 모든 cgi 변수와 쿠키이름(COOKIES_NAMES)이나 쿠키값(COOKIES_VALUES)등 많은 변수를 제공한다.
SecAuditEngine On SecAuditLog logs/audit_log |
기본적으로 제공하는 아파치 로그는 그다지 많은 정보를 제공하지 않는다.
따라서 위와 같이 설정할 경우 필터링에 매칭되는 요청에 대해서 logs/audit_log 파일에 상세한 정보를 제공하도록 한다.
만약, filter에 걸리는 정보만 로그에 남기려면 On 대신 RelevantOnly를 지정하면 된다.
아래의 경우 미리 설정되어 있던 /etc/passwd 파일에 대한 요청이 필터링 되어 로그에 남은 예를 보여주고 있다.
.
Request: 202.69.81.170 - - [Fri Aug 29 15:37:00 2007] "GET /................../etc/passwd HTTP/1.0" 500 600 Handler: (null) Error: mod_security: Access denied with code 500. Pattern match "/etc/passwd" at THE_REQUEST. ---------------------------------------- GET /................../etc/passwd HTTP/1.0 Connection: Keep-Alive Content-Length: 0 Host: server User-Agent: Mozilla/4.75 (Nikto/1.30 ) mod_security-message: Access denied with code 500. Pattern match "/etc/passwd" at THE_REQUEST. mod_security-action: 500
|
SecServerSignature "Microsoft-IIS/5.0" |
mod_security의 재미있는 기능중 하나는 바로 서버명이나 버전 등의 정보를 임의로 위조할 수 있다.
는 것이다.
. 앞에서 살펴본 바와 같이 apache라는 서버 명을 변경하려면 아파치 소스에서 직접 변경하고, 재 컴파일 하여야 하는데, 그럴 필요 없이 위와 같이 설정하기만 하면 외부에서 볼 때는 apache가 아닌 IIS로 보일 것이다.
. 아래는 위와 같이 설정하였을 때 로그에 보이는 정보이다.
. 제대로 적용되려면 httpd.conf에서 ServerTokens Full로 설정되어 있어야 한다.
[Fri Jun 11 04:02:28 2007] [notice] Microsoft-IIS/5.0 mod_ssl/2.8.12 OpenSSL/0.9.6b configured -- resuming normal operations |
이외 보안문제를 해결하기 위한 몇 가지 권장 설정이 있는데, 참고하기 바란다.
SecFilter "\.\./" |
만약 요청 중 "../"이 포함되어 있다.
면 이는 상위 디렉토리에 접근하기 위한 시도임을 알 수 있는데, 일부 정상적인 프로그램에서도 보이는 경우가 있으므로 일정기간 모니터링이 필요하다.
SecFilter "<[[:space:]]*script" SecFilter "<(.|\n)+>" |
Cross site scripting (XSS) attacks에 대비하기 위한 설정으로 XSS 공격은 공격자가 HTML이나 자바 스크립트 등을 웹 페이지에 몰래 삽입하여 다른 유저가 실행하도록 하여 쿠키 등의 정보를 획득하는 것을 말한다.
SecFilter "delete[[:space:]]+from" SecFilter "insert[[:space:]]+into" SecFilter "select.+from" |
SQL Injection등 SQL과 관련된 공격을 차단하고자 할 때 사용할 수 있다.
. 그러나 잘못 사용하였을 경우에는 정상적인 SQL 질의도 필터링 되므로 실제 적용시 주의하여야 한다.
SecFilterSelective "HTTP_CONTENT_TYPE" multipart/form-data <Location "/upload.php"> SecFilterInheritance Off </Location> |
웹 서버를 통해 파일 업로드를 제한하되 특정 디렉토리 이하에만 허용하도록 설정할 수 있다.
. 위와 같이 설정하였을 경우 /upload.php를 통해서만 파일 업로드를 허용한다.
modsecurity 2.x의 경우 많은 기능이 추가되면서 Core rules라는 이름으로 별도의 룰파일이 제공되고 있다.
. modsecurity_crs_10_config.conf는 기본 config 파일이고, 나머지 파일이 core rules가 된다.
Core rules는 각각의 룰 파일에 설명이 자세하게 언급되어 있고 1.x와 크게 다르지는 않지만 대표적인 몇 가지만 살펴보도록 하자.
- modsecurity_crs_10_config.conf
modsecurity의 기본 정책을 설정하는 룰이다.
.
SecRuleEngine (On|Off|DetectionOnly) |
초기에는 탐지 모드인 DetectionOnly로 운영하다가 이후에 On으로 변경하여 사용하면 된다.
SecAuditLogType (Serial|Concurrent) |
이벤트에 대한 로그파일을 한 파일에 남기도록 할 것인지(Serial) 아니면 따로 남도록 할 것인지(Concurrent)에 대한 설정이다.
.
SecServerSignature "Microsoft IIS/5.0“ |
1.x와 같이 헤더에 보이는 서버 정보를 변경하기 위한 설정으로 제대로 적용되려면 ServerTokens Full로 설정되어 있어야 한다.
SecUploadDir /tmp SecUploadKeepFiles (On|Off|RelevantOnly) |
업로드되는 파일에 대해 임시로 저장될 디렉토리와 업로드 된 파일을 서버에 별도로 저장할 것인지에 대한 설정을 정의하는 것이다.
. On은 저장, Off는 저장하지 않는 것이고
RelevantOnly는 의심이 가는 파일을 저장하는 것이다.
.
- modsecurity_crs_15_customrules.conf
이 파일은 원래 존재하지 않지만 각자 생성하기 바란다.
이 룰에 특정 ip에서의 접속은 차단하지 않는 등의 whitelist룰을 정의하면 된다.
- modsecurity_crs_20_protocol_violations(21_protocol_anomalies).conf
http 프로토콜의 입장에서 비정상적인 요청을 탐지하고 차단하는 룰이다.
.
SecRule REQUEST_METHOD "^(GET|HEAD)$""chain,deny,log,auditlog,status:400, msg:'GET or HEAD requests with bodies', severity:'2',id:'960011'" SecRule REQUEST_HEADERS:Content-Length "!^0?$" |
매우 복잡해 보이는 룰인데, 찬찬히 뜯어보면 이해가 될 것이다.
. 이는 GET이나 HEAD 메소드에서 Content-Length가 0이 아닌 요청에 대해 차단하는 룰인데, 여기에서 chain을 이용하면 뒤에 나오는 룰과 and 연산하겠다는 의미가 되는데, 여러 개의 and 연산을 원하면 원하는 만큼 chain이 가능하다.
SecRule REQUEST_URI ^http:/ "deny,log,auditlog,status:400, msg:'Proxy access attempt', severity:'2',id:'960014'" |
이는 URI에 http://가 포함된 proxy와 같은 요청을 차단하는 룰이다.
. 일반적인 경우 URI에 http://가 포함되지 않는다.
SecRule &REQUEST_HEADERS:Host "@eq 0" "skip:1,log,auditlog, msg:'Request Missing a Host Header',id:'960008',severity:'4'" SecRule REQUEST_HEADERS:Host "^$" "log,auditlog,msg:'Request Missing a Host Header',id:'960008',severity:'4'" |
이는 요청 헤더에 Host: 가 없는 접속에 대해 탐지하는 룰로서 첫 번째의 경우 변수앞에 &이 있는데, 이는 뒤에 나오는 Host 헤더의 개수를 의미하는 것이다.
. 따라서 이 룰은 Host 헤더의 개수가 0개인(eq 0) 즉, Host 헤더 자체가 없는 요청을 탐지하는 것이며 두 번째의 경우 시작을 의미하는 ^과 끝을 의미하는 $이 바로 연속되어 있으므로 내용이 없는 즉 비어있는 것을 의미하므로 Host 헤더는 있지만 Host의 내용이 없는 요청을 탐지하는 것이다.
.
SecRule REQUEST_HEADERS:Host "^[\d\.]+$" "deny,log,auditlog,status:400, msg:'Host header is a numeric IP address', severity:'2',id:'960017'“ |
이는 초기에 탐지모드로 설정 시 가장 많은 오탐(false positive)를 유발하는 것으로 Host에 도메인이 아닌 ip주소로 접속하는 것을 탐지하는 것으로 이를테면 http://192.168.1.10/
과 같은 접속을 탐지하는 것이다.
. 일반적이지는 않지만 정상적인 경우도 많이 있으므로 이 룰은 탐지하지 않도록 하는 것이 좋다.
SecRule REQUEST_URI ^http:/ "deny,log,auditlog,status:400, msg:'Proxy access attempt', severity:'2',id:'960014'" |
- modsecurity_crs_30_http_policy.conf
http에 대한 정책을 제한 설정하는 룰이다.
.
SecRule REQUEST_METHOD "!^((?:(?:POS|GE)T|OPTIONS|HEAD))$" \ "phase:1,log,auditlog,status:501,msg:'Method is not allowed by policy', severity:'2',id:'960032'" |
이는 앞에서로 언급한 바 있는데, 미리 지정한 메소드 외에는 차단하는 설정을 보여주고 있다.
.
SecRule REQUEST_BASENAME "\.ba(?:[kt]|ckup)|exe|key|mdb|old)$" \ "t:urlDecodeUni, t:lowercase, deny,log,auditlog,status:500, msg:'URL file extension is restricted by policy', severity:'2',id:'960035'" |
웹을 통한 파일의 확장자를 제한하는 것으로 흔히 정보유출이 될 수 있는 backup, exe, mdb등의 확장자에 대해서는 접속을 차단하는 설정이다.
. inc, bak, tgz등도 차단하는 것이 좋다.
- modsecurity_crs_35_bad_robots.conf
스팸봇이나 스캐너 등의 User-Agent에 대해 차단하는 룰이다.
.
SecRule HTTP_User-Agent "n(?:-stealth|sauditor|essus|ikto)|(?:jaascoi|paro)s|\.nasl)" \ "deny,log,auditlog,status:404,msg:'Request Indicates a Security Scanner Scanned the Site',id:'990002',severity:'2'" |
이는 nikto, nessus, paros등 해킹 등에 악용되는 스캐너 및 툴 등에 대해 차단하는 설정으로 User-Agent 정보를 가지고 차단하는 설정이다.
. 그러나 User-Agent는 클라이언트가 설정하는 것으로 공격자 입장에서 쉽게 변경이 가능하며 대부분의 공격 툴에서는 이를 변경할 수 있는 옵션을 제공하고 있으므로 스크립트키드의 단순스캔이나 공격만 차단하는데 사용될 수 있다.
라는 것을 참고만 하기 바란다.
- modsecurity_crs_40_generic_attacks.conf
웹해킹에 대한 핵심적인 룰이라고 할 수 있는데, php injection / sql injection / 시스템 command 에 대한 차단 룰이다.
.
SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES|REQUEST_HEADERS|!REQUEST_HEADERS:Referer “dbms_java)\b|i(?:n(?:to\b\W*?\b(?:dump|out)file|sert\b\W*?\binto|ner\b\W*?\bjoin)\b|(?:f(?:\b\W*?\(\W*?\bbenchmark|null\b)|snull\b)\W*?\()|(?:having|or|and)\b\s+?(?:\d{1,10}|'[^=]{1,10}')\s*?[=<>]+|(?:print\]\b\W*?\@|root)\@|c(?:ast\b\W*?\(|oalesce\b))|(?:;\W*?\b(?:shutdown|drop)|\@\@version)\b|'(?:s(?:qloledb|a)|msdasql|dbo)')" \"capture,t:replaceComments,ctl:auditLogParts=+E,log,auditlog,msg:'SQL Injection Attack. Matched signature <%{TX.0}>',id:'950001',severity:'2'“ |
정규식으로 되어 있어 룰이 상당히 복잡해 보이는데, 각종 sql injection을 훌륭하게 차단하는 룰이다.
. 특별히 수정할 내용은 없다.
SecRule ARGS|ARGS_NAMES|REQUEST_HEADERS "echo\b\W*?\by+)\b|c(?:md(?:(?:32)?\.exe\b|\b\W*?\/c)|d(?:\b\W*?[\\\/]|\W*?\.\.)|hmod.{0,40}?\+.{0,3}x))|[\;\|\`]\W*?\b(?:(?:c(?:h(?:grp|mod|own|sh)|md|pp|c)|p(?:asswd|ython|erl|ing|s)|n(?:asm|map|c )|f(?:inger|tp)|(?:kil|mai)l|(?:xte)?rm|ls(?:of)?|telnet|uname|echo|id)\b|g(?:\+\+|cc\b))|\/(?:c(?:h(?:grp|mod|own|sh)|pp|c)|p(?:asswd|ython|erl|ing|s)|telnet|uname|echo|id)( ?:['\"\|\;\`\-\s]|$))“ \"capture,ctl:auditLogParts=+E,deny,log,auditlog,status:501,msg:'System Command Injection. Matched signature <%{TX.0}> ',id:'950006',severity:'2'" |
웹을 통한 chmod, kill, echo, id등 각종 시스템 명령어에 대한 접근을 차단하는 룰이다.
.
- modsecurity_crs_45_trojans.conf
백도어나 일부 웹 쉘 등의 파일에 대한 접근을 탐지하는 룰이다.
.
SecRule REQUEST_FILENAME "root\.exe" \ "t:urlDecodeUni,t:htmlEntityDecode,ctl:auditLogParts=+E,deny,log,auditlog,status:404,msg:'Backdoor access',id:'950921',severity:'2'“ |
코드레드 백도어인 root.exe에 대한 접근을 탐지하는 룰이다.
.
- modsecurity_crs_50_outbound.conf
공격자들은 sql injection등을 실행시 서버에 비정상적인 데이터를 보내어 출력되는 에러값을 통해 db등의 각종 정보를 수집하게 된다.
이 룰은 이름이 의미하는 바대로 클라이언트에게 보여 지는 출력 값에 특정한 문자열이 포함되면 비정상 요청이라 판단하여 탐지하거나 차단하는 룰이다.
.
SecRule RESPONSE_BODY "(?:>\ [To Parent Directory\]<\/[Aa]><br>|<title>Index of.*?<h1>Index of)" \ "ctl:auditLogParts=+E,deny,log,auditlog,status:403,msg:'Directory Listing',id:'970013',tag:'LEAKAGE/INFO',severity:'4'" |
위의 룰은 httpd.conf에서 indexes가 설 정시 디렉토리가 그대로 리스팅 되는 것을 차단하는 것으로 만약 특정 디렉토리에 index.html 등의 파일이 없을 경우 아래 그림과 같이 디렉토리 구조가 그대로 보이게 된다.
따라서 위의 룰이 활성화되었을 경우에는 403 에러가 나게 될 것이다.
.
[그림] indexes가 설정시 화면
지금까지 대략의 룰을 살펴보았는데 앞에서도 언급했듯이 어떤 보안솔루션이든 커스터마이징이라는 단계를 반드시 거쳐야 한다.
특히 오탐도 적지 않게 있는 것이 사실인데, 몇 가지만 살펴보도록 하자.
- modsecurity 1.x
➀ SecFilterSelective ARGS "-->" "msg:'XSS attack'"
SecRule ARGS "-->" "msg:'XSS attack'"
이는 XSS 공격을 탐지하기 위한 룰인데, 데이터에 --> 만 들어가도 공격으로 판단하게 된다.
이를테면 게시판에 “123 --> 456” 과 같은 글이 올라오면 공격으로 판단하게 된다.
➁ mod_security-message: Access denied with code 403. Error processing request body: Multipart: final boundary missing [severity "EMERGENCY"]
이 에러는 파일 업로드 시 일부 발생하는 것으로 알려져 있다.
. 개발자는 파일 전송 시 네트워크 등의 문제로 인한 것이라고 하는데, 1.9.x의 버그가 아닌가 한다.
이 문제를 해결하려면 SecFilterScanPOST On을 Off로 변경하여야 한다.
➂ mod_security-message: Access denied with code 403. Pattern match ";[[:space:]]*(ls|id|pwd|wget|cd)" at ARGS_VALUES("content") [msg "Command execution attack"] [severity "EMERGENCY"]
이는 웹을 통해 시스템의 특정 명령어를 실행하는 것을 탐지하는 룰인데,
http://www.example.com/example.php?board=public&id=1225 와 같이 id=xxxx는 정상 사이트에서도 자주 사용되므로 오탐의 여지가 있으므로 id 부분은 빼는 것이 좋다.
➃ SecFilterSelective ARGS "alert[[:space:]]*\(“
이 역시 XSS 공격을 탐지하는 것인데 아래와 같은 경우 공격으로 오탐하므로 이 역시 해제하는 것이 좋다.
<SCRIPT LANGUAGE="JAVASCRIPT">
function openerTr()
{
alert("팝업이 차단되었습니다!");
}
</SCRIPT>
➄ SecFilterSelective ARGS "http-equiv“
SecFilterSelective ARGS "style[[:space:]]*=“
각각 다음의 경우 공격으로 판단하므로 역시 오탐이다.
.
<meta http-equiv="Content-Type“
<style type="text/css">
- modsecurity 2.x
➀ Message: Warning. Operator EQ match: 0. [id "960008"] [msg "Request Missing a Host Header"] [severity "WARNING"]
이는 앞에서 살펴본 바와 같이 요청에 Host헤더가 없는 경우 탐지하는 것인데 적지 않은 프로그램들이 이러한 경우가 많다. 이를테면 모니터링을 위해 많이 사용하고 있는 와츠업(Whats'Up)의 경우도 다음과 같이 Host 헤더가 없다.
HEAD / HTTP/1.0
Accept: */*
User-Agent: WhatsUp Professional/1.0
➁ SecRule REQUEST_LINE
"!^[a-z]{3,10}\s*(?:\w{3,7}?\:\/\/[\w\-\.\/]*)??\/[\w\-\.\/~%:@&=+$,;]*(?:\?[\S]*)??\s*http\/\d\.\d$" \
"t:none,t:lowercase,deny,log,auditlog,status:400,msg:'Invalid HTTP Request Line',,id:'960911',severity:'2'"
이는 요청한 파일이나 디렉토리명에 공란이 있거나 story(McGrawHill)cover.jpg와 같이 특수문자가 있을 경우 탐지하게 된다.
실제로 표준은 아니지만 많은 사이트에서 이러한 형태의 파일명을 사용하는 것이 사실이므로 탐지에서 제외하는 것이 좋다.
➂ SecAuditLogRelevantStatus "^[45]“
위의 의미는 400이나 500 계열 에러에 대해 로그를 남기도록 하는 설정인데, 이와 같이 설정시에는 404 Not Found에 대해서도 로그를 남기게 되는데, 이렇게 되면 너무 많은 정보가 남게 되므로 이를 아래와 같이 와 같이 변경하는 것이 좋다.
이러한 경우 404는 로그에 남기지 않아 로그의 양을 대폭 줄일 수 있다.
.
SecAuditLogRelevantStatus "^(?:5|4\d[^4])"
범용적으로 보이는 오탐을 살펴보았는데, 좀 더 세밀한 오탐은 각자의 사이트에서 직접 확인하는 수 밖에는 없을 것이다.
.
다음으로는 modsecurity 운영 시 필요한 몇 가지 팁을 살펴보도록 하자.
- 특정한 ip에 대해서는 모니터링 하지 않을 때
관리자나 사무실ip등 특정한 ip에 대해서는 별도의 탐지나 차단을 하지 않고자 할 때는 다음과 같은 룰을 설정하면 된다.
(1.x의 경우)
SecRule REMOTE_ADDR "^192\.168\.1\100$"
phase:1,nolog,allow,ctl:ruleEngine=Off,ctl:auditEngine=Off
위의 경우 192.168.1.100에 대해서는 모니터링하지 않는 것을 뜻한다.
이러한 whitelist룰은 modsecurity_crs_15_customrules.conf 와 같은 룰을 만들어 반드시 10과 20 사이의 룰에 정의하도록 하여야 한다.
반대로 특정한 접속에 대해 차단하는 blacklist 룰을 생성하려면 이를테면 modsecurity_crs_60_customrules.conf 와 같이 50 이상의 룰을 생성하도록 한다.
반대로 특정 ip 또는 특정 URI에 대한 상세 정보를 남기도록 하려면 아래와 같은 룰을 설정하면 된다.
(2.x의 경우)
SecRule REMOTE_ADDR "^192\.168\.10\.69$“
phase:1,log,pass,ctl:debugLogLevel=9
SecRule REQUEST_URI "^/path/to/script.pl$" phase:1,log,pass,ctl:debugLogLevel=9
- 특정 도메인(디렉토리)에 대해서는 모니터링하지 않을 때
1.x의 경우 해당 디렉토리에 다음과 같은 .htaccess를 설정하면 된다.
SecFilterEngine Off # 기본 엔진 동작 정지
SecFilterScanPOST Off # POST 스캔 중지
SecFilterCheckURLEncoding Off # URL 인코딩 체크 중지
참고로 .htaccess 에 #이 있을 경우 500 error가 발생하므로 그대로 복사할 경우 서비스가 되지 않을 수 있으므로 주석(#) 부분은 명기하지 않아야 함을 주의하기 바란다.
그런데, modsecurity 2.x 에서는 .htaccess를 지원하지 않는다는 점을 주의하기 바란다.
만약 2.x에서 .htaccess를 설정하면 다음과 같은 error_log가 남게 된다.
SecRuleEngine not allowed here.
2.x에서의 룰은 다음과 같이 설정하면 된다.
SecRule REQUEST_HEADERS:Host "^www.foo.com$"
"allow,phase:1,nolog,ctl:ruleEngine=Off”
또는 해당 도메인을 지정한 VirtualHost에서 SecRuleEngine Off를 지정해도 된다.
- 특정 도메인에서 특정 룰을 해제하려고 할 때
만약 특정 도메인에서 룰id가 950005인 룰을 해제하려면 다음과 같이 VirtualHost에서 설정해 주면 된다.
<VirtualHost 192.168.1.4>
ServerAdmin webmaster@example.com
DocumentRoot /home/example/public_html
ServerName example.com
SecRuleRemoveById 950005
</VirtualHost>
modsecurity와 같은 보안 프로그램에서는 매번 쌓이는 탐지 로그 관리가 중요하다.
그러나 다른 보안 솔루션도 그렇듯이 처음에는 얼마간 모니터링하다가 엄청나게 쌓이는 로그에 결국은 흐지부지되어 보지 않게 되는 경우가 많은데, modsecurity에서는 2.x 버전에 호환되는 modsecurity console이라는 별도의 web기반의 GUI 프로그램을 무료로 제공하고 있어 쉬운 로그관리가 가능하다.
이 프로그램은 1개의 콘솔에서 3개의 센서까지 가능하며 로그에 대한 검색, 보고서 작성등의 기능을 기간제한 없이 제공하고 있는데, console 프로그램 자체에 웹과 db를 통합 하여 제공하는 패키지이므로 별도의 프로그램을 설치할 필요가 없다. 이 프로그램은 jdk/jre 1.4 이상에서 작동하므로 다음과 같이 http://java.sun.com/ 에서 이를테면 jdk1.5를 사전에 다운로드 및 설치하여야 한다.
# ./jdk-1_5_0_09-linux-i586.bin
이후 아래와 같이 INSTALL4J_JAVA_HOME 환경변수를 지정한 후 console을 압축해제한 디렉토리에서 실행을 하면 8886/tcp에서 리슨하게 된다.
# export INSTALL4J_JAVA_HOME=/usr/local/src/modsecurity-console/jdk1.5.0_09 # ./modsecurity-console start
이어 룰에 다음과 같이 설정하면 되는데, 여기에서 modsec-auditlog-collector.pl 파일은 http://server.com:8886/ 에 접속하면 다운로드할 수 있다.
.
SecAuditLogType Concurrent SecAuditLogParts ABCDEFGHZ SecAuditLogStorageDir /usr/local/apache2/logs/data/ SecAuditLog /usr/local/apache2/logs/modsec-audit.log SecAuditLog "|/usr/local/apache2/bin/modsec-auditlog-collector.pl \ /usr/local/apache2/logs/data/ /usr/local/apache2/logs/modsec-audit.log"
modsec-auditlog-collector.pl 에서는 아래의 부분만 지정해 주면 되는데, 여기에서 id/pw는 Sensors => Add Sensor 에 보이는 콘솔 화면에서 동일하게 설정해 주면 된다.
my $CONSOLE_HOST = "218.236.43."; // 콘솔이 설치된 서버의 ip my $CONSOLE_PORT = "8886"; // 콘솔 port my $CONSOLE_USERNAME = "alpha1"; // 콘솔에서 생성한 센서의 id my $CONSOLE_PASSWORD = "sensor1"; // 콘솔에서 생성한 센서의 pw
그리고 콘솔에서 필요한 라이센스는 https://bsn.breach.com/ 에 회원가입 후 바로 발급받을 수 있다.
.
|
- 부가 기능
최근 버전의 modsecurity 에서는 다음과 같은 재미있는 기능도 제공하고 있다.
.
# Increase the IP collection score based on filter hits
SecRule REQUEST_FILENAME “/cgi-bin/phf" pass,setvar:ip.score=+10
SecRule REQUEST_FILENAME “cmd.exe” pass,setvar:ip.score=+20
SecRule REQUEST_METHOD “TRACE” pass,setvar:ip.score=+5
# Evaluate the overall IP collection score
SecRule IP:SCORE "@ge 30“
이는 일정 시간동안 특정한 점수(score)이상이 될 경우 탐지하는 룰로서 위의 예의 경우 /cgi-bin/phf을 요청할 경우 +10점을, cmd.exe에 접근 시 +20점 그리고 TRACE 메소드 요청 시 +5점을 주게 되고 만약 한 ip에서의 합계가 30점을 넘을 경우 공격으로 판단. 차단하도록 하는 룰이다.
. 아래는 위의 룰을 통해 차단된 예를 보여주고 있다.
.
Modsec_debug.log : [Thu Nov 01 15:51:17 2007] [error] [client 192.168.69.32] ModSecurity: Access denied with code 403 (phase 2). Operator GE match: 30. [hostname “server.com"] [uri "/"] [unique_id "ehPwUdrsK0sAAG-@A3YAAAAA"]
또한 다음과 같은 geoip기능도 제공하고 있어 국가별 차단 기능도 제공하고 있다.
.
SecGeoLookupsDb /usr/local/geo/data/GeoLiteCity.datSecRule
REMOTE_ADDR "@geoLookup" chain,drop,msg:'Non-KR IP address'
SecRule GEO:COUNTRY_CODE "!@streq KR“
위의 경우 한국ip대역이 아닌 접속은 차단하는 것을 보여주고 있는데, 이보다는 다음과 같이 iptables 방화벽을 이용하여 커널레벨에서 접근 통제 설정하는 것이 더 권장되는데 iptables에 대한 자세한 내용은 뒤에서 다시 살펴보기로 하겠다.
iptables -A INPUT -m geoip ! --src-cc KR -j DROP
그리고, mod_security를 적용하였을 때 성능적인 측면을 고려하지 않을 수 없다. 그러나 테스트한 바에 따르면 모듈 적용이후 80% 정도의 성능을 보였지만 꼭 필요한 룰만 설정하여 좀 더 룰을 커스터마이징한다면 보안을 강화하면서도 거의 정상적인 성능을 기대할 수 있을 것이다.
.
rule | 성능(Requests per second) | 퍼센트(%) |
무설정시 | 841.04 [#/sec] | 100% |
20_protocol_violations | 795.54 [#/sec] | 94% |
21_protocol_anomalies | 806.45 [#/sec] | 96% |
30_http_policy | 801.28 [#/sec] | 95% |
35_bad_robots | 800.64 [#/sec] | 95% |
40_generic_attacks | 724.64 [#/sec] | 86% |
45_trojans | 794.28 [#/sec] | 94% |
50_outbound | 766.28 [#/sec] | 91% |
40/50만 적용시 | 686.81 [#/sec] | 81% |
모두 적용시 | 634.12 [#/sec] | 75% |
[표] ab -n 1000 -c 100 http://target_server/test.cgi 으로 테스트 결과
이외에도 많은 유용한 기능과 새로운 기능을 제공하고 있으므로 더 많은 예는 관련 홈페이지를 참고하기 바란다.
http://modsecurity.org/ : modsecurity 공식 홈페이지
http://www.krcert.or.kr/firewall2/ : KISA의 modsecurity 무상 기술지원 사이트
http://gotroot.com/ : modsecurity 관련 많은 룰 제공(최근 업데이트 없음)
상용 웹방화벽(WAF-Web Application Firewall)이 제공하는 방식과 modsecurity의 제공 방식에 대해 각자 비교해 보고 장단점을 비교해 보기 바란다.
참고로 대부분의 상용제품에서는 사용상의 편의로 브리지 방식이 많이 채택되는 추세이다.
.
[표] 웹방화벽 구현 방식의 차이 | ||||||||||||||||||||||||||||||
|
관련자료
-
이전
-
다음