waf: WAF de alto rendimiento construido sobre la pila nginx-module-lua
Instalación
Si aún no has configurado la suscripción al repositorio RPM, regístrate. Luego, puedes proceder con los siguientes pasos.
CentOS/RHEL 7 o Amazon Linux 2
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install lua-resty-waf
CentOS/RHEL 8+, Fedora Linux, Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-waf
Para usar esta biblioteca Lua con NGINX, asegúrate de que nginx-module-lua esté instalado.
Este documento describe lua-resty-waf v0.11.1 lanzado el 09 de mayo de 2017.
lua-resty-waf es un WAF de proxy inverso construido utilizando la pila OpenResty. Utiliza la API Lua de Nginx para analizar la información de las solicitudes HTTP y procesarla contra una estructura de reglas flexible. lua-resty-waf se distribuye con un conjunto de reglas que imita el CRS de ModSecurity, así como algunas reglas personalizadas creadas durante el desarrollo y pruebas iniciales, y un pequeño conjunto de parches virtuales para amenazas emergentes. Además, lua-resty-waf se distribuye con herramientas para traducir automáticamente las reglas existentes de ModSecurity, lo que permite a los usuarios extender la implementación de lua-resty-waf sin necesidad de aprender una nueva sintaxis de reglas.
lua-resty-waf fue desarrollado inicialmente por Robert Paprocki para su tesis de maestría en la Universidad del Gobernador de Occidente.
./configure --with-pcre=/path/to/pcre/source --with-pcre-jit
Puedes descargar la fuente de PCRE desde el [sitio web de PCRE](http://www.pcre.org/). Consulta también esta [entrada de blog](https://www.cryptobells.com/building-openresty-with-pcre-jit/) para un recorrido paso a paso sobre cómo construir OpenResty con una biblioteca PCRE habilitada para JIT.
## Rendimiento
lua-resty-waf fue diseñado con eficiencia y escalabilidad en mente. Aprovecha el modelo de procesamiento asíncrono de Nginx y un diseño eficiente para procesar cada transacción lo más rápido posible. Las pruebas de carga han mostrado que las implementaciones que utilizan todos los conjuntos de reglas proporcionados, que están diseñados para imitar la lógica detrás del CRS de ModSecurity, procesan transacciones en aproximadamente 300-500 microsegundos por solicitud; esto equivale al rendimiento anunciado por [el WAF de Cloudflare](https://www.cloudflare.com/waf). Las pruebas se realizaron en una pila de hardware razonable (CPU E3-1230, 32 GB de RAM, 2 x 840 EVO en RAID 0), alcanzando aproximadamente 15,000 solicitudes por segundo. Consulta [esta entrada de blog](http://www.cryptobells.com/freewaf-a-high-performance-scalable-open-web-firewall) para más información.
La carga de trabajo de lua-resty-waf está casi exclusivamente limitada por la CPU. La huella de memoria en la VM de Lua (excluyendo el almacenamiento persistente respaldado por `lua-shared-dict`) es de aproximadamente 2 MB.
## make && sudo make install
Alternativamente, instala a través de Luarocks:
### process_multipart_body
*Predeterminado* verdadero
Habilita el procesamiento de cuerpos de solicitudes multipart/form-data (cuando están presentes), utilizando el módulo `lua-resty-upload`. En el futuro, lua-resty-waf puede usar este procesamiento para realizar verificaciones más estrictas de los cuerpos de carga; por ahora, este módulo realiza solo verificaciones mínimas de sanidad en el cuerpo de la solicitud y no registrará un evento si el cuerpo de la solicitud es inválido. Desactiva esta opción si no necesitas esta verificación, o si los errores en el módulo de upstream están causando problemas con las cargas HTTP.
*Ejemplo*:
```lua
location / {
access_by_lua_block {
-- deshabilitar el procesamiento de solicitudes multipart/form-data
-- ten en cuenta que el cuerpo de la solicitud aún se enviará al upstream
waf:set_option("process_multipart_body", false)
}
}
req_tid_header
Predeterminado: falso
Establece un encabezado HTTP X-Lua-Resty-WAF-ID en la solicitud de upstream, con el valor como el ID de transacción. Este ID se correlacionará con el ID de transacción presente en los registros de depuración (si está configurado). Esto puede ser útil para el seguimiento de solicitudes o fines de depuración.
Ejemplo:
location / {
access_by_lua_block {
waf:set_option("req_tid_header", true)
}
}
res_body_max_size
Predeterminado: 1048576 (1 MB)
Define el umbral de longitud de contenido más allá del cual los cuerpos de respuesta no serán procesados. Este tamaño del cuerpo de respuesta se determina mediante el encabezado de respuesta Content-Length. Si este encabezado no existe en la respuesta, el cuerpo de la respuesta nunca será procesado.
Ejemplo:
location / {
access_by_lua_block {
-- aumentar el tamaño máximo de respuesta a 2 MB
waf:set_option("res_body_max_size", 1024 * 1024 * 2)
}
}
res_body_mime_types
Predeterminado: "text/plain", "text/html"
Define los tipos MIME con los que lua-resty-waf procesará el cuerpo de la respuesta. Este valor se determina mediante el encabezado Content-Type. Si este encabezado no existe, o el tipo de respuesta no está en esta lista, el cuerpo de la respuesta no será procesado. Establecer esta opción añadirá el tipo MIME dado a los valores predeterminados existentes de text/plain y text/html.
Ejemplo:
location / {
access_by_lua_block {
-- los tipos MIME que serán procesados ahora son text/plain, text/html y text/json
waf:set_option("res_body_mime_types", "text/json")
}
}
Se pueden agregar múltiples tipos MIME pasando una tabla de tipos a set_option.
res_tid_header
Predeterminado: falso
Establece un encabezado HTTP X-Lua-Resty-WAF-ID en la respuesta de downstream, con el valor como el ID de transacción. Este ID se correlacionará con el ID de transacción presente en los registros de depuración (si está configurado). Esto puede ser útil para el seguimiento de solicitudes o fines de depuración.
Ejemplo:
location / {
access_by_lua_block {
waf:set_option("res_tid_header", true)
}
}
score_threshold
Predeterminado: 5
Establece el umbral para la puntuación de anomalías. Cuando se alcanza el umbral, lua-resty-waf denegará la solicitud.
Ejemplo:
location / {
access_by_lua_block {
waf:set_option("score_threshold", 10)
}
}
storage_backend
Predeterminado: dict
Define un motor a utilizar para el almacenamiento persistente de variables. Las opciones actualmente disponibles son dict (zona de memoria compartida ngx_lua), memcached, y redis.
Ejemplo:
location / {
acccess_by_lua_block {
waf:set_option("storage_backend", "memcached")
}
}
storage_keepalive
Predeterminado: verdadero
Habilita o deshabilita TCP keepalive para conexiones a hosts de almacenamiento persistente remotos.
Ejemplo:
location / {
acccess_by_lua_block {
waf:set_option("storage_keepalive", false)
}
}
storage_keepalive_timeout
Predeterminado: 10000
Configura (en milisegundos) el tiempo de espera para el grupo de keepalive de cosocket para hosts de almacenamiento persistente remotos.
Ejemplo:
location / {
acccess_by_lua_block {
waf:set_option("storage_keepalive_timeout", 30000)
}
}
storage_keepalive_pool_size
Predeterminado: 100
Configura el tamaño del grupo para el grupo de keepalive de cosocket para hosts de almacenamiento persistente remotos.
Ejemplo:
location / {
acccess_by_lua_block {
waf:set_option("storage_keepalive_pool_size", 50)
}
}
storage_memcached_host
Predeterminado: 127.0.0.1
Define un host a utilizar cuando se usa memcached como motor de almacenamiento persistente de variables.
Ejemplo:
location / {
acccess_by_lua_block {
waf:set_option("storage_memcached_host", "10.10.10.10")
}
}
storage_memcached_port
Predeterminado: 11211
Define un puerto a utilizar cuando se usa memcached como motor de almacenamiento persistente de variables.
Ejemplo:
location / {
acccess_by_lua_block {
waf:set_option("storage_memcached_port", 11221)
}
}
storage_redis_host
Predeterminado: 127.0.0.1
Define un host a utilizar cuando se usa redis como motor de almacenamiento persistente de variables.
Ejemplo:
location / {
acccess_by_lua_block {
waf:set_option("storage_redis_host", "10.10.10.10")
}
}
storage_redis_port
Predeterminado: 6379
Define un puerto a utilizar cuando se usa redis como motor de almacenamiento persistente de variables.
Ejemplo:
location / {
acccess_by_lua_block {
waf:set_option("storage_redis_port", 6397)
}
}
storage_zone
Predeterminado: ninguno
Define el lua_shared_dict que se utilizará para almacenar datos de almacenamiento persistente. Esta zona debe definirse en el bloque http{} de la configuración.
Ejemplo:
http {
-- define una zona de memoria compartida de 64M para almacenar datos de almacenamiento persistente
lua_shared_dict persistent_storage 64m;
}
location / {
access_by_lua_block {
waf:set_option("storage_zone", "persistent_storage")
}
}
Se pueden definir y utilizar múltiples zonas compartidas, aunque solo se puede definir una zona por ubicación de configuración. Si una zona se llena y la interfaz del diccionario compartido no puede agregar claves adicionales, se registrará lo siguiente en el registro de errores:
Error al agregar clave al almacenamiento persistente, aumenta el tamaño de lua_shared_dict
Manejo de Fases
lua-resty-waf está diseñado para ejecutarse en múltiples fases del ciclo de vida de la solicitud. Las reglas se pueden procesar en las siguientes fases:
- access: La información de la solicitud, como URI, encabezados de solicitud, argumentos de URI y cuerpo de solicitud están disponibles en esta fase.
- header_filter: Los encabezados de respuesta y el estado HTTP están disponibles en esta fase.
- body_filter: El cuerpo de respuesta está disponible en esta fase.
- log: Los registros de eventos se escriben automáticamente al finalizar esta fase.
Estas fases corresponden a sus respectivos controladores lua de Nginx (access_by_lua, header_filter_by_lua, body_filter_by_lua, y log_by_lua, respectivamente). Ten en cuenta que ejecutar lua-resty-waf en un controlador de fase lua que no esté en esta lista llevará a un comportamiento roto. Todos los datos disponibles en una fase anterior están disponibles en una fase posterior. Es decir, los datos disponibles en la fase access también están disponibles en las fases header_filter y body_filter, pero no viceversa.
Conjuntos de Reglas Incluidos
lua-resty-waf se distribuye con varios conjuntos de reglas que están diseñados para imitar la funcionalidad del CRS de ModSecurity. Para referencia, estos conjuntos de reglas se enumeran aquí:
- 11000_whitelist: Política local de listas blancas
- 20000_http_violation: Violación del protocolo HTTP
- 21000_http_anomaly: Anomalías del protocolo HTTP
- 35000_user_agent: Agentes de usuario maliciosos/sospechosos
- 40000_generic_attack: Ataques genéricos
- 41000_sqli: SQLi
- 42000_xss: XSS
- 90000_custom: Reglas personalizadas/parcheo virtual
- 99000_scoring: Manejo de puntuaciones de anomalías
Definiciones de Reglas
lua-resty-waf analiza las definiciones de reglas a partir de blobs JSON almacenados en disco. Las reglas se agrupan según su propósito y severidad, definidas como un conjunto de reglas. Los conjuntos de reglas incluidos fueron creados para imitar alguna funcionalidad del CRS de ModSecurity, particularmente las definiciones de base_rules. Además, el script incluido modsec2lua-resty-waf.pl se puede usar para traducir conjuntos de reglas adicionales o personalizados a un blob JSON compatible con lua-resty-waf.
Ten en cuenta que hay varias limitaciones en el script de traducción, con respecto a acciones, colecciones y operadores no soportados. Consulta esta página de wiki para obtener una lista actualizada de incompatibilidades conocidas.
Notas
Solicitudes de Extracción
Por favor, dirija todas las solicitudes de extracción hacia la rama de desarrollo, o una rama de características si la PR es un cambio significativo. Los commits a master deben venir solo en forma de actualizaciones de documentación u otros cambios que no tengan impacto en el módulo en sí (y que puedan fusionarse limpiamente en desarrollo).
Hoja de Ruta
- Conjunto de reglas de parches virtuales ampliado: Aumentar la cobertura de amenazas emergentes.
- Pruebas de integración/aceptación ampliadas: Aumentar la cobertura de amenazas comunes y escenarios de uso.
- Traducciones de sintaxis de ModSecurity ampliadas: Soportar más operadores, variables y acciones.
- Perfiles de aplicación comunes: Conjuntos de reglas ajustados para CMS/aplicaciones comunes.
- Soporte para múltiples objetivos de registro de socket/archivo: Probablemente requiera bifurcar el proyecto lua-resty-logger-socket.
Limitaciones
lua-resty-waf está en continuo desarrollo y mejora, y como tal, puede estar limitado en su funcionalidad y rendimiento. Las limitaciones actualmente conocidas se pueden encontrar en el rastreador de problemas de GitHub para este repositorio.
Véase También
- El proyecto OpenResty: http://openresty.org/
- Mi blog personal para actualizaciones y notas sobre el desarrollo de lua-resty-waf: http://www.cryptobells.com/tag/lua-resty-waf/
GitHub
Puedes encontrar consejos de configuración adicionales y documentación para este módulo en el repositorio de GitHub para nginx-module-waf.