En el corazón de cada WAF vive el conjunto de reglas: una colección de declaraciones condicionales que definen cuándo es permitido, registrado o bloqueado el tráfico. Estas reglas son legibles para los humanos.
Ejemplo Real de Regla
La mejor manera de aprender sobre estas reglas es profundizar sobre una. La siguiente regla es para SQLi y es del OWASP CRS v3.3.7:
SecRule REQUEST_BASENAME "@detectSQLi" \ "id:942101,\ phase:2,\ block,\ capture,\ t:none,t:utf8toUnicode,t:urlDecodeUni,t:removeNulls,\ msg:'SQL Injection Attack Detected via libinjection',\ logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\ tag:'application-multi',\ tag:'language-multi',\ tag:'platform-multi',\ tag:'attack-sqli',\ tag:'OWASP_CRS',\ tag:'capec/1000/152/248/66',\ tag:'PCI/6.5.2',\ tag:'paranoia-level/3',\ ver:'OWASP_CRS/3.3.7',\ severity:'CRITICAL',\ setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}',\ setvar:'tx.anomaly_score_pl3=+%{tx.critical_anomaly_score}'"
El trigger: SecRule REQUEST_BASENAME "@detectSQLi"
En la primera linea, tenemos lo siguiente:
SecRule: Directiva de ModSecurity estándar para definir una regla.REQUEST_BASENAME: Esta variable se refiere al nombre del archivo o endpoint en la ruta URL. Por ejemplo, en/api/user/123el basename es123."@detectSQLi": Es una llamada alibinjection, una librería C especializada diseñada sólo para detectar inyecciones SQL.
Rule Metadata: Identity, Context, and Compliance En las siguientes cuatro lineas tenemos lo siguiente:
id:942101: Identificador único (parte del esquema de numeración CRS).phase:2: Corre durante el procesado del body de la petición (después de los headers, antes de la lógica de la app).block: Toma acción: rechaza la petición.capture: Guarda el payload con coincidencia para registro (%{TX.0}).
Input Normalisation: Seeing Through the Noise
Antes de que @detectSQLi corra, el input es normalizado a través de una pipeline de transformaciones:
t:none: Comienza con input crudo.t:utf8toUnicode: Convierte las secuencias UTF-8 a Unicode para prevenir bypass vía encoding.t:urlDecodeUni: Realiza decoding recursivo de la URL (%2527se decodea en%27que se decodea en').t:removeNulls: Corta bytes nulos (%00), normalmente usados para terminar strings en parsers basados en C.
Es crucial decodear los contenidos antes de comprobar, de otra forma, sería fácil perderse amenazas encodeadas.
Logging and Attribution: Making Incidents Actionable En las siguientes dos líneas, registramos una alerta legible por humanos:
msg:'SQL Injection Attack Detected via libinjection',\ logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\
msg: Alerta humanamente legible que se muestra en logs y SIEM.logdata: Detalle forense rico.%{TX.0}: El payload exacto que disparó la regla.%{MATCHED_VAR_NAME}: Qué variable fue inspeccionada.%{MATCHED_VAR}: El valor completo de la variable.
Tags: Connecting to Standards and Strategy Ahora es hora de etiquetar el tráfico. Los tags no son sólo etiquetas, sino que son ganchos operacionales. Considera el siguiente ejemplo:
tag:'attack-sqli' tag:'OWASP_CRS' tag:'capec/1000/152/248/66' tag:'PCI/6.5.2' tag:'paranoia-level/3'
Las lineas de arriba indican lo siguiente:
capec/1000/152/248/66: Se relaciona con CAPEC (Common Attack Pattern Enumeration).PCI/6.5.2: Hace referencia a PCI DSS requirement para proteger contra debilidades de inyección.paranoia-level/3: CRS usa cuatro niveles de paranoia. PL3 es más estricto y bloquea más, pero tiene más falsos positivos.
Scoring and Telemetry: Feeding the Anomaly Engine Finalmente, podemos usar el tráfico detectado para actualizar nuestra puntuación de riesgos. Echa un vistazo más cercano a las siguientes dos lineas:
setvar:'tx.sql_injection_score=+%{tx.critical_anomaly_score}' setvar:'tx.anomaly_score_pl3=+%{tx.critical_anomaly_score}'
Hacen lo siguiente:
tx.sql_injection_score: Rastrea riesgo acumulativo SQLi a lo largo de múltiples reglas.tx.anomaly_score_pl3: Le da al CRS la puntuación con nivel de paranoia 3.
