waf: WAF de alto desempenho construído na pilha nginx-module-lua
Instalação
Se você ainda não configurou a assinatura do repositório RPM, inscreva-se. Depois, você pode prosseguir com os seguintes passos.
CentOS/RHEL 7 ou 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 com o NGINX, certifique-se de que o nginx-module-lua está instalado.
Este documento descreve lua-resty-waf v0.11.1 lançado em 09 de maio de 2017.
lua-resty-waf é um WAF de proxy reverso construído usando a pilha OpenResty. Ele utiliza a API Lua do Nginx para analisar informações de solicitações HTTP e processá-las contra uma estrutura de regras flexível. lua-resty-waf é distribuído com um conjunto de regras que imita o ModSecurity CRS, além de algumas regras personalizadas criadas durante o desenvolvimento e testes iniciais, e um pequeno conjunto de patches virtuais para ameaças emergentes. Além disso, lua-resty-waf é distribuído com ferramentas para traduzir automaticamente regras existentes do ModSecurity, permitindo que os usuários estendam a implementação do lua-resty-waf sem a necessidade de aprender uma nova sintaxe de regras.
lua-resty-waf foi inicialmente desenvolvido por Robert Paprocki para sua tese de mestrado na Western Governor's University.
./configure --with-pcre=/path/to/pcre/source --with-pcre-jit
Você pode baixar a fonte do PCRE no [site do PCRE](http://www.pcre.org/). Veja também este [post no blog](https://www.cryptobells.com/building-openresty-with-pcre-jit/) para um passo a passo sobre como construir o OpenResty com uma biblioteca PCRE habilitada para JIT.
## Desempenho
lua-resty-waf foi projetado com eficiência e escalabilidade em mente. Ele aproveita o modelo de processamento assíncrono do Nginx e um design eficiente para processar cada transação o mais rápido possível. Testes de carga mostraram que implantações que implementam todos os conjuntos de regras fornecidos, que são projetados para imitar a lógica por trás do ModSecurity CRS, processam transações em aproximadamente 300-500 microsegundos por solicitação; isso equivale ao desempenho anunciado pelo [WAF da Cloudflare](https://www.cloudflare.com/waf). Os testes foram realizados em uma pilha de hardware razoável (CPU E3-1230, 32 GB de RAM, 2 x 840 EVO em RAID 0), atingindo cerca de 15.000 solicitações por segundo. Veja [este post no blog](http://www.cryptobells.com/freewaf-a-high-performance-scalable-open-web-firewall) para mais informações.
A carga de trabalho do lua-resty-waf é quase exclusivamente dependente da CPU. A pegada de memória na VM Lua (excluindo armazenamento persistente suportado por `lua-shared-dict`) é de aproximadamente 2MB.
## make && sudo make install
Alternativamente, instale via Luarocks:
### process_multipart_body
*Padrão* true
Habilita o processamento de corpos de solicitações multipart/form-data (quando presentes), usando o módulo `lua-resty-upload`. No futuro, o lua-resty-waf pode usar esse processamento para realizar verificações mais rigorosas nos corpos de upload; por enquanto, este módulo realiza apenas verificações mínimas de sanidade no corpo da solicitação e não registrará um evento se o corpo da solicitação for inválido. Desative esta opção se você não precisar dessa verificação, ou se bugs no módulo upstream estiverem causando problemas com uploads HTTP.
*Exemplo*:
```lua
location / {
access_by_lua_block {
-- desabilitar o processamento de solicitações multipart/form-data
-- observe que o corpo da solicitação ainda será enviado para o upstream
waf:set_option("process_multipart_body", false)
}
}
req_tid_header
Padrão: false
Define um cabeçalho HTTP X-Lua-Resty-WAF-ID na solicitação upstream, com o valor como o ID da transação. Este ID irá correlacionar-se com o ID da transação presente nos logs de depuração (se definido). Isso pode ser útil para rastreamento de solicitações ou fins de depuração.
Exemplo:
location / {
access_by_lua_block {
waf:set_option("req_tid_header", true)
}
}
res_body_max_size
Padrão: 1048576 (1 MB)
Define o limite de comprimento do conteúdo além do qual os corpos de resposta não serão processados. Esse tamanho do corpo da resposta é determinado pelo cabeçalho de resposta Content-Length. Se esse cabeçalho não existir na resposta, o corpo da resposta nunca será processado.
Exemplo:
location / {
access_by_lua_block {
-- aumentar o tamanho máximo da resposta para 2 MB
waf:set_option("res_body_max_size", 1024 * 1024 * 2)
}
}
res_body_mime_types
Padrão: "text/plain", "text/html"
Define os tipos MIME com os quais lua-resty-waf processará o corpo da resposta. Este valor é determinado pelo cabeçalho Content-Type. Se esse cabeçalho não existir, ou o tipo de resposta não estiver nesta lista, o corpo da resposta não será processado. Definir esta opção adicionará o tipo MIME fornecido aos padrões existentes de text/plain e text/html.
Exemplo:
location / {
access_by_lua_block {
-- os tipos MIME que serão processados agora são text/plain, text/html e text/json
waf:set_option("res_body_mime_types", "text/json")
}
}
Vários tipos MIME podem ser adicionados passando uma tabela de tipos para set_option.
res_tid_header
Padrão: false
Define um cabeçalho HTTP X-Lua-Resty-WAF-ID na resposta downstream, com o valor como o ID da transação. Este ID irá correlacionar-se com o ID da transação presente nos logs de depuração (se definido). Isso pode ser útil para rastreamento de solicitações ou fins de depuração.
Exemplo:
location / {
access_by_lua_block {
waf:set_option("res_tid_header", true)
}
}
score_threshold
Padrão: 5
Define o limite para a pontuação de anomalias. Quando o limite é atingido, lua-resty-waf negará a solicitação.
Exemplo:
location / {
access_by_lua_block {
waf:set_option("score_threshold", 10)
}
}
storage_backend
Padrão: dict
Define um mecanismo a ser usado para armazenamento persistente de variáveis. As opções atualmente disponíveis são dict (zona de memória compartilhada ngx_lua), memcached e redis.
Exemplo:
location / {
acccess_by_lua_block {
waf:set_option("storage_backend", "memcached")
}
}
storage_keepalive
Padrão: true
Habilita ou desabilita o TCP keepalive para conexões com hosts de armazenamento persistente remotos.
Exemplo:
location / {
acccess_by_lua_block {
waf:set_option("storage_keepalive", false)
}
}
storage_keepalive_timeout
Padrão: 10000
Configura (em milissegundos) o tempo limite para o pool de keepalive de cosocket para hosts de armazenamento persistente remotos.
Exemplo:
location / {
acccess_by_lua_block {
waf:set_option("storage_keepalive_timeout", 30000)
}
}
storage_keepalive_pool_size
Padrão: 100
Configura o tamanho do pool para o pool de keepalive de cosocket para hosts de armazenamento persistente remotos.
Exemplo:
location / {
acccess_by_lua_block {
waf:set_option("storage_keepalive_pool_size", 50)
}
}
storage_memcached_host
Padrão: 127.0.0.1
Define um host a ser usado ao usar memcached como um mecanismo de armazenamento persistente de variáveis.
Exemplo:
location / {
acccess_by_lua_block {
waf:set_option("storage_memcached_host", "10.10.10.10")
}
}
storage_memcached_port
Padrão: 11211
Define uma porta a ser usada ao usar memcached como um mecanismo de armazenamento persistente de variáveis.
Exemplo:
location / {
acccess_by_lua_block {
waf:set_option("storage_memcached_port", 11221)
}
}
storage_redis_host
Padrão: 127.0.0.1
Define um host a ser usado ao usar redis como um mecanismo de armazenamento persistente de variáveis.
Exemplo:
location / {
acccess_by_lua_block {
waf:set_option("storage_redis_host", "10.10.10.10")
}
}
storage_redis_port
Padrão: 6379
Define uma porta a ser usada ao usar redis como um mecanismo de armazenamento persistente de variáveis.
Exemplo:
location / {
acccess_by_lua_block {
waf:set_option("storage_redis_port", 6397)
}
}
storage_zone
Padrão: none
Define o lua_shared_dict que será usado para armazenar dados de armazenamento persistente. Esta zona deve ser definida no bloco http{} da configuração.
Exemplo:_
http {
-- define uma zona de memória compartilhada de 64M para armazenar dados de armazenamento persistente
lua_shared_dict persistent_storage 64m;
}
location / {
access_by_lua_block {
waf:set_option("storage_zone", "persistent_storage")
}
}
Várias zonas compartilhadas podem ser definidas e usadas, embora apenas uma zona possa ser definida por localização de configuração. Se uma zona ficar cheia e a interface do dicionário compartilhado não puder adicionar chaves adicionais, a seguinte mensagem será registrada no log de erros:
Erro ao adicionar chave ao armazenamento persistente, aumente o tamanho do lua_shared_dict
Manipulação de Fases
lua-resty-waf é projetado para ser executado em várias fases do ciclo de vida da solicitação. As regras podem ser processadas nas seguintes fases:
- access: Informações da solicitação, como URI, cabeçalhos da solicitação, argumentos da URI e corpo da solicitação estão disponíveis nesta fase.
- header_filter: Cabeçalhos de resposta e status HTTP estão disponíveis nesta fase.
- body_filter: O corpo da resposta está disponível nesta fase.
- log: Logs de eventos são automaticamente escritos ao final desta fase.
Essas fases correspondem aos manipuladores Lua apropriados do Nginx (access_by_lua, header_filter_by_lua, body_filter_by_lua e log_by_lua, respectivamente). Observe que executar lua-resty-waf em um manipulador de fase Lua que não está nesta lista levará a um comportamento quebrado. Todos os dados disponíveis em uma fase anterior estão disponíveis em uma fase posterior. Ou seja, os dados disponíveis na fase access também estão disponíveis nas fases header_filter e body_filter, mas não vice-versa.
Conjuntos de Regras Incluídos
lua-resty-waf é distribuído com vários conjuntos de regras que são projetados para imitar a funcionalidade do ModSecurity CRS. Para referência, esses conjuntos de regras estão listados aqui:
- 11000_whitelist: Política local de whitelist
- 20000_http_violation: Violação do protocolo HTTP
- 21000_http_anomaly: Anomalias do protocolo HTTP
- 35000_user_agent: Agentes de usuário maliciosos/suspeitos
- 40000_generic_attack: Ataques genéricos
- 41000_sqli: SQLi
- 42000_xss: XSS
- 90000_custom: Regras personalizadas/patching virtual
- 99000_scoring: Manipulação de pontuação de anomalias
Definições de Regras
lua-resty-waf analisa definições de regras a partir de blobs JSON armazenados em disco. As regras são agrupadas com base em propósito e severidade, definidas como um conjunto de regras. Os conjuntos de regras incluídos foram criados para imitar algumas funcionalidades do ModSecurity CRS, particularmente as definições de base_rules. Além disso, o script incluído modsec2lua-resty-waf.pl pode ser usado para traduzir conjuntos de regras adicionais ou personalizados para um blob JSON compatível com lua-resty-waf.
Observe que existem várias limitações no script de tradução, em relação a ações, coleções e operadores não suportados. Consulte esta página da wiki para uma lista atualizada de incompatibilidades conhecidas.
Notas
Pull Requests
Por favor, direcione todos os pull requests para o branch de desenvolvimento, ou um branch de recurso se o PR for uma mudança significativa. Commits para o master devem vir apenas na forma de atualizações de documentação ou outras mudanças que não impactem o módulo em si (e possam ser mescladas de forma limpa no desenvolvimento).
Roteiro
- Conjunto de regras de patch virtual expandido: Aumentar a cobertura de ameaças emergentes.
- Testes de integração/aceitação expandidos: Aumentar a cobertura de ameaças comuns e cenários de uso.
- Traduções de sintaxe do ModSecurity expandidas: Suportar mais operadores, variáveis e ações.
- Perfis de aplicação comuns: Conjuntos de regras ajustados para CMS/aplicações comuns.
- Suporte a vários alvos de logger de socket/arquivo: Provavelmente requer bifurcação do projeto lua-resty-logger-socket.
Limitações
lua-resty-waf está em desenvolvimento e melhoria contínuos e, como tal, pode ser limitado em sua funcionalidade e desempenho. Limitações atualmente conhecidas podem ser encontradas no rastreador de problemas do GitHub para este repositório.
Veja Também
- O projeto OpenResty: http://openresty.org/
- Meu blog pessoal para atualizações e notas sobre o desenvolvimento do lua-resty-waf: http://www.cryptobells.com/tag/lua-resty-waf/
GitHub
Você pode encontrar dicas adicionais de configuração e documentação para este módulo no repositório do GitHub para nginx-module-waf.