Hlavní navigace

Webový aplikační firewall: logování a jednotlivé fáze ModSecurity

Michal Vymazal

V minulém dílu jsme si popsali základní vlastnosti, instalaci a výchozí konfiguraci modulu ModSecurity. V dnešním dílu se podíváme se na logování a jednotlivé fáze ModSecurity.

Doba čtení: 9 minut

Sdílet

Většinu níže uvedeného najdete samozřejmě v ModSecurity Reference Manual. Ten má pouhých 100 stran, aktuální verze je 2.x – v textu níže se jedná o verzi 2.9.2. Já se zde pokusím popsat ty nejpoužívanější.

Logování

Pojďme se nyní podívat na některé důležité direktivy, které se týkají vlastního logování. Všechny tyto parametry se nastavují v konfiguračním souboru  /etc/modsecurity/modsecurity.conf.

Jednou z nejdůležitějších věcí je samozřejmě umístění vlastního logovacího souboru a metoda zápisu do tohoto souboru.

# Výstupní log bude umístěn do souboru
# /var/log/apache2/modsec_audit.log
# Vlastní zápis do logu bude probíhat do jediného logovacího souboru (Serial)

SecAuditLogType

Popis: Určuje typ použitého logovacího mechanismu.

Syntaxe: SecAuditLogType Serial | Concurrent

Serial: Všechny výstupy budou zapsány do jediného logovacího souboru, jehož umístění je dáno parametrem SecAuditLog. Tato metoda je vhodná ve většině případů, může ale mít dopad na výkonnost serveru, protože současně je možné do logu zapsat pouze výstupy z jedné transakce. Výstupy z ostatních transakcí tak budou muset být zapsány později.

Concurrent: Pro výstupy z každé transakce je použit samostatný logovací soubor. Takto lze zaznamenávat výstupy z řady paralelních transakcí. Tuto metodu budete muset zvolit při tzv. vzdáleném logování (remote logging).

SecAuditLog

Popis: Určuje cestu k vlastnímu logovacímu souboru (serial logging format) nebo k indexovému souboru pro tzv. souběžné logování (concurrent logging format). Pokud je použit v kombinaci s mlogc (pouze v případě concurrent logging format), pak tato direktiva určuje umístění mlogc indexu.

Syntaxe: SecAuditLog /cesta/k souboru/modsec_audit.log

Soubor modsec_audit.log bude použit k ukládání výstupů z jednotlivých transakcí za předpokladu, že je nastavena metoda serial audit logging format.

Pokud je zvolena metoda concurrent audit logging format, pak bude tento soubor používán jako index a bude obsahovat záznam o všech vytvořených logovacích souborech (pro každou transakci jeden logovací soubor).

Máte-li v úmyslu použít metodu concurrent audit logging k zasílání logů na vzdálený server, je třeba aktivovat ModSecurity Log Collector (mlogc) takto:

SecAuditLog "|/cesta/k modulu/mlogc /cesta/k souboru/mlogc.conf"

Poznámka: Logovací soubor je většinou vytvořen při startu www démona, který je obvykle spuštěn pod právy systémového uživatele root. Uživatelům, kteří nedisponují právy root (může se jednat o skutečné uživatelské účty nebo o další systémové uživatele), raději nepřidělujte práva k zápisu do tohoto souboru.

V našem případě tedy budou výše popsané direktivy nastaveny takto:

SecAuditLogType Serial
SecAuditLog /var/log/apache2/modsec_audit.log

Nyní určíme, co vše vlastně chceme do souboru logovat a v jakém rozsahu:

# Tyto tři řádky
# určují, co bude zapsáno do logovacího souboru
SecAuditEngine RelevantOnly
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
SecAuditLogParts ABIJDEFHZ

Řádky 1 a 2 znamenají, že pouze odpovídající chybové kódy 5XX (server error) nebo 4×x (client error) budou zapsány do logu. Kód 404 (not found) nebude do logu zaznamenán. Tímto způsobem ovlivňujeme délku a čitelnost logovacího souboru.

Podívejme se nyní na jednotlivé direktivy blíže.

SecAuditEngine

Popis: Určuje rozsah zápisu do logovacího souboru.

Syntaxe: SecAuditEngine Off | On | RelevantOnly

Přednastavená hodnota (Default): Off

Tato direktiva umožňuje zapsat do logovacího souboru pouze relevantní výstupy z jednotlivých transakcí. Vlastní filtr je pak dán direktivou SecAuditLogRelevantStatus.

Významy jednotlivých přepínačů jsou tyto:

On: loguje všechny transakce

Off: neloguje nic

RelevantOnly: jsou zalogovány pouze transakce, které byly vyhodnoceny jako varování nebo chyba, nebo mají relevantní status code (což je vymezeno direktivou SecAuditLogRelevantStatus)

Poznámka: Pokud chcete změnit možnosti logování na bázi určité transakce (tedy v závislosti na datech z této transakce) použijte volbu ctl.

SecAuditLogRelevantStatus

Popis: Nastavuje filtr pro transakce, které budou zapsány do logu (relevant status code).
Syntaxe: SecAuditLogRelevan­tStatus REGEX

Příklad použití:  SecAuditLogRelevantStatus "^(?:5|4(?!04))"

Závislosti/Poznámka: Direktiva SecAuditEngine musí být nastavena na hodnotu RelevantOnly.

Hlavním smyslem této direktivy je umožnit pouze zápis relevantních transakcí a „zpřehlednit“ tak zápis v logu. REGEX (Regular Expression – regulární výraz) v příkladu způsobí, že do logu budou zahrnuty stavy s chybovým kódem 5×x a 4×x, nicméně stavy (transakce) s kódem 404 (stránka nenalezena) budou vynechány. Tohoto výsledku lze samozřejmě docílit i pravidlem, aktivovaným ve fázi 5, ale SecAuditLogRelevantStatus je pokládán za lepší řešení, protože bude fungovat i za stavu, kdy SecRuleEngine je zakázán (potlačen).

SecAuditLogParts

Popis: Určuje strukturu vlastního logu, konkrétně, které části transakce budou do logu zapsány.

Syntaxe: SecAuditLogParts PARTLETTERS

Příklad použití: SecAuditLogParts ABCFHZ

Přednastavená hodnota (Default): ABCFHZ

Přípustné možnosti jsou tyto:

  • A – audit log header
  • B – request headers
  • C – request body
  • D – intended response header (not implemented yet)
  • E – intended response body
  • F – response headers
  • G – response body
  • H – audit log trailer
  • I – reduced multipart request body
  • J – multipart files information
  • K – matched rules
  • Z – audit log footer

Poznámka: Sekce K se zdá býti lákavá, avšak ve skutečnosti způsobí podobný zápis do logu:

===Ukázka výpisu z logu=====
--c3910b46-K--  
          
SecAction "phase:1,id:900001,t:none,setvar:tx.critical_anomaly_score=5,setvar:tx.error_anomaly_score=4,setvar:tx.warning_anomaly_score=3,setvar:tx.notice_anomaly_score=2,no
log,pass"
                                  
SecAction "phase:1,id:900002,t:none,setvar:tx.anomaly_score=0,setvar:tx.sql_injection_score=0,setvar:tx.xss_score=0,setvar:tx.inbound_anomaly_score=0,setvar:tx.outbound_ano
maly_score=0,nolog,pass"                                                                                                    
SecAction "phase:1,id:900003,t:none,setvar:tx.inbound_anomaly_score_level=5,setvar:tx.outbound_anomaly_score_level=4,nolog,pass"                                      
SecAction "phase:1,id:900006,t:none,setvar:tx.max_num_args=255,nolog,pass"                        
SecRule "REQUEST_HEADERS:User-Agent" "@rx ^(.*)$" "phase:1,id:900018,t:none,t:sha1,t:hexEncode,setvar:tx.ua_hash=%{matched_var},nolog,pass"                                  
                                     
SecRule "&TX:REAL_IP" "@eq 0" "phase:1,id:900021,t:none,initcol:global=global,initcol:ip=%{remote_addr}_%{tx.ua_hash},setvar:tx.real_ip=%{remote_addr},nolog,pass"           
                                    
SecRule "REQUEST_METHOD" "@rx ^POST$" "phase:1,log,msg:'POST request missing Content-Length Header.',severity:4,id:960012,ver:OWASP_CRS/2.2.9,rev:1,maturity:9,accuracy:9,bl
ock,logdata:%{matched_var},t:none,tag:OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ,tag:CAPEC-272,chain"
======Konec ukázky výpisu z logu=======

Což není příliš přehledné, doporučuji sekci K nechat vypnutou a ID jednotlivých pravidel identifikovat podle záznamu z /var/log/apache2/error.logZde je zápis přehlednější. 

===Ukázka výpisu z logu=====
ModSecurity: Access denied with code 403 (phase 4). Pattern match "^5\\\\d{2}$" at RESPONSE_STATUS. [file "/usr/share/modsecurity-crs/activated_rules/modsecurity_crs_50_outbound.conf"] [line "53"] [id "970901"] [rev "2"] [msg "The application is not available"] [data
"Matched Data: 503 found within RESPONSE_STATUS: 503"] [severity "ERROR"] [ver "OWASP_CRS/2.2.9"] [maturity "9"] [accuracy "9"] [tag "WASCTC/WASC-13"] [tag "OWASP_TOP_10/A
6"] [tag "PCI/6.5.6"] [hostname "xxxx.xxxx.xxxx"] [uri "/remote.php/webdav/"] [unique_id "WQMM@38AAQEAABrqNT8AAAAK"]
======Konec ukázky výpisu z logu=======

Vlastní ID daného CRS pravidla je v logu dobře čitelné. V našem případě to je id „970901“.

Jednotlivé fáze ModSecurity

V originále jsou nazývány „Processing Phases“, přičemž každá transakce projde všemi těmito fázemi. Jednotlivá pravidla pak lze „umístit k vyhodnocení“ vždy do jedné z těchto fází:

  1. Request headers (REQUEST_HEADERS)
  2. Request body (REQUEST_BODY)
  3. Response headers (RESPONSE_HEADERS)
  4. Response body (RESPONSE_BODY)
  5. Logging (LOGGING)

Diagram znázorňující standardní cyklus vyhodnocování transakcí je uveden níže. Zahrnuje všech pět fází:


Výběr fáze, ve které dojde k „aktivaci“ našeho pravidla provádíme buď přímo v definici daného pravidla pomocí parametru phase nebo prostřednictvím direktivy  SecDefaultAction:

SecDefaultAction "log,pass,phase:2,id:4"
SecRule REQUEST_HEADERS:Host "!^$" "deny,phase:1,id:5"

Poznámka: Data, dostupná prostřednictvím každé fáze, jsou kumulativní. To znamená, že průchodem do dalších fází získáte k dané transakci více a více dat.

Poznámka: Mějte na paměti, že pravidla jsou vyhodnocována vždy v té fázi, která je pro dané pravidlo určena (pokud pravidlo neobsahuje parametr phase, pak je mu phase určena direktivou SecDefaultAction).

Poznámka: Fáze LOGGING se provede bez ohledu na to, co se odehrálo v předchozích fázích. K jejímu naplnění dojde VŽDY na konci každé transakce.

Fáze Request Headers

Pravidla jsou v této fázi zprocesována ihned poté, co Apache načte hlavičky jednotlivých požadavků (post-read-request phase). Vlastní tělo požadavku (transakce) ještě načteno nebylo, takže o něm zatím nic nevíme. Do této fáze tedy začleňujeme ta pravidla, která chceme zprocesovat ještě před načtením vlastního těla požadavku (request body). Tímto způsobem můžeme rozhodovat, zda celý požadavek bude odmítnut (deny), bude načten nebo porovnáván s jiným vzorem (parse as XML).

Poznámka: Pravidla v této fázi nemohou ovlivňovat tzv. Apache scope directives (Directory, Location, LocationMatch, apod. ), protože nebyly načteny jejich parametry (post-read-request hook). Výjimkou je pouze direktiva VirtualHost.

Pokud potřebujete využít pravidla ModSecurity ve spolupráci s Apache locations, učiňte tak v Phase 2. Viz diagram Apache Request Cycle/ModSecurity Processing Phases.

Fáze Request Body

Hlavní fáze pro vstupní analýzu jednotlivých transakcí. V této fázi bude pracovat většina pravidel zaměřených na „chování“ aplikací. V této fázi dochází k načtení celého těla požadavku (transakce). ModSecurity podporuje celkem tři typy dat v rámci request body: 

  • application/x-www-form-urlencoded - přenos dat ve formulářích
  • multipart/form-data - přenos dat / souborů
  • text/xml - parsování XML dat

Ostatní typy dat většina aplikací příliš nepoužívá.

Poznámka: Pokud chcete přistupovat k datům ve fázi Request Body, je třeba nastavit direktivu SecRequestBodyAccess na hodnotu On (konfigurační soubor  /etc/modsecurity/modsecurity.conf).

Fáze Response Headers

Tato fáze „vstupuje na scénu“ před odesláním hlaviček odpovědí (response headers) ve směru ze serveru ke klientovi. Je tedy možné vyhodnocovat hlavičky jednotlivých odpovědí ještě před jejich odesláním (v závislosti na hlavičce pak můžete např. ukládat response body apod.).

Některé status codes (např. 404) jsou vyhodnocovány již v dřívějších cyklech a zde nemusejí být vyhodnoceny správně. Naproti tomu některé response headers jsou u Apache procesovány až v následujících průchodech (např. Date, Server a Connection), takže v této fázi rovněž není dobré je vyhodnocovat. Jejich vyhodnocení je rozumnější ve fázi 5 (logging) nebo na samostatné proxy.

Fáze Response Body

Hlavní fáze pro výstupní analýzu jednotlivých transakcí. Zde můžete zkoumat výstupní HTML kód, chybové zprávy nebo chybná přihlašování (ověřování).

Poznámka: Pokud chcete přistupovat k datům ve fázi Response Body, je třeba nastavit direktivu SecResponseBodyAccess na hodnotu On (konfigurační soubor  /etc/modsecurity/modsecurity.conf).

Fáze Logging

Tato fáze přichází na scénu před započetím vlastního procesu logování událostí (transakcí). Pravidla, začleněná do této fáze, mohou ovlivňovat způsob vlastního logování. Je možné zde zkoumat chybová hlášení zalogovaná webovým démonem Apache. Nelze však provádět operace typu deny/block.

Vlastní strukturu a tvorbu CRS pravidel si ukážeme v některém z příštích dílů seriálu. Níže uvádím ukázku pravidel, která zamezí volání aplikací na vašem www serveru skrze IP adresu. Veškeré aplikace tedy musejí být volány skrze doménové jméno (např. www.mojedomena.cz).

/usr/share/modsecurity-crs/direct_ip_access.conf

# Initialize the IP collection
SecAction "phase:1,nolog,pass,initcol:ip=%{REMOTE_ADDR},id:'9999015'"

# Do not process if the remote ip is an local ip
SecRule REMOTE_ADDR "^192\.168\.10\.\d+$" "phase:1,log,allow,ctl:ruleEngine=Off,id:'9999016'"

# Block direct ip access. Access will be blocked for this ip for 2 days
SecRule REQUEST_HEADERS:Host "^[\d.:]+$" "phase:2,rev:'2',t:none,deny,setvar:ip.blocked=1,expirevar:ip.blocked=1728000,msg:'Host header is a numeric IP address',logdata:'%{
matched_var}',severity:'4',id:'9999017',tag:'OWASP_CRS/PROTOCOL_VIOLATION/IP_HOST'"

# Example: Block IP for 300 seconds
#SecRule ARGS blockme "phase:2,block,setvar:ip.blocked=1,expirevar:ip.blocked=300"

# Enforce blocking
SecRule IP:BLOCKED "@eq 1" "phase:1,deny,log,id:'9999018'"