Pular para conteúdo

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)
    }
}
Observe que, por natureza, é necessário armazenar em buffer todo o corpo da resposta para usar adequadamente a resposta como uma coleção, portanto, aumentar significativamente esse número não é recomendado sem justificativa (e recursos de servidor adequados).

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

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.