Categoria: Segurança

  • Gestão centralizada de identidade e autenticação com Keycloak

    Keycloak é uma solução de IAM – Identity and Access Management – de código aberto desenvolvida pela Red Hat, que a utilizou como base para seu produto Red Hat Single Sign-On. Ele atua como um provedor de identidade e permite centralizar a autenticação e autorização para aplicativos e sistemas em ambientes corporativos.

    A centralização da autenticação e da identidade de acesso traz vantagens no aspecto de segurança. Autenticação em múltiplos fatores e requisitos de senha podem ser impostos e, para a suspensão de um acesso, basta fazê-lo em um só lugar, sendo mais rápido e sem a chance de um outro acesso ser esquecido e mantido ativo como pode acontecer quando a identidade é distribuída em diferentes sistemas.

    Keycloak é distribuído de algumas formas, entre elas os famosos pacotes de arquivo ZIP e TAR, bem como contêiner Docker, o que facilita a implantação e manutenção em ambientes de produção. Mas como esse projeto teve o objetivo de entender como funciona a aplicação, o arquivo foi escolhido.

    Para a execução do Keycloak, será criado um usuário de serviço dedicado.

    # useradd -m -d /opt/keycloak -s /usr/sbin/nologin keycloak

    Keycloak é uma aplicação em Java e atualmente a documentação recomenda o OpenJDK 25. Além disso, ele utiliza o PostgreSQL. As configurações suportadas podem ser verificadas no link:

    Considerando um sistema RHEL 10.2:

    # dnf install java-25-openjdk postgresql-server

    Configure o PostgreSQL substituindo o tipo de autenticação ident em conexões do tipo host por scram-sha-256, que utiliza senha. O ident utiliza o usuário no sistema operacional para autenticar no servidor de banco de dados, de forma similar ao peer mas para conexões TCP em vez de socket unix. Para isso, seria necessário utilizar um serviço de ident.

    # postgresql-setup --initdb
    # sed -i 's/ident/scram-sha-256/g' /var/lib/pgsql/data/pg_hba.conf
    # systemctl enable --now postgresql.service

    Criando o banco de dados no PostgreSQL:

    # sudo -u postgres psql
    postgres=# CREATE ROLE keycloak_op WITH LOGIN PASSWORD 'key&peele';
    postgres=# CREATE DATABASE keycloak_db OWNER keycloak_op TEMPLATE template0 ENCODING 'UTF8';

    Então, podemos executar o shell como o usuário de serviço criado para baixar e configurar o Keycloak:

    # sudo -u keycloak bash
    
    $ wget -P /tmp https://github.com/keycloak/keycloak/releases/download/26.7.4/keycloak-26.7.4.tar.gz
    
    $ tar -xzvf /tmp/keycloak-26.7.4.tar.gz -C /opt/keycloak --strip-components=1
    
    $ chmod +x /opt/keycloak/bin/*

    O Keycloak tem um arquivo de configuração em /opt/keycloak/conf/keycloak.conf, onde é necessário determinar os seguintes parâmetros:

    db=postgres
    db-username=keycloak_op
    db-password=key&peele
    db-url=jdbc:postgresql://localhost/keycloak_db
    hostname=https://keycloak.exemplo.com
    
    # Configuração para uso com o proxy reverso HTTP, desabilitando SSL
    http-enabled=true
    proxy-headers=xforwarded
    proxy-trusted-addresses=192.168.1.10

    O template da configuração também oferece os parâmetros de certificado e chave SSL. Por padrão, o Keycloak escuta nas portas 8080 para HTTP e 8443 para HTTPS. No entanto, com o https:// especificado no parametro hostname ele já entende que no proxy reverso o acesso será feito pela porta padrão 443.

    O Keycloak é compilado utilizando um framework chamado Quarkus, que faz uma espécie de intermediação entre o Java e o Keycloak. Quando uma aplicação inicia, o Quarkus tem uma sequência de etapas de descoberta dos componentes da aplicação. Uma recomendação é otimizar esse processo do Quarkus com uma espécie de “snapshot” que ele faz dos componentes da aplicação a serem iniciados, o que permite o Keycloak iniciar mais rápido.

    $ /opt/keycloak/bin/kc.sh build

    Então a aplicação pode ser testada com essa otimização sendo executada como:

    $ /opt/keycloak/bin/kc.sh start --optimized

    O comando de otimização deve ser executado novamente após atualizações do Keycloak. Falta agora criar o administrador inicial da aplicação no banco de dados.

    $ /opt/keycloak/bin/kc.sh bootstrap-admin user

    De volta ao shell como administrador ou root, é necessário agora liberar a porta para HTTP no firewall.

    # firewall-cmd --permanent --add-port=8080/tcp
    # firewall-cmd --reload

    Criando um arquivo para a unidade de serviço do systemd em /etc/systemd/system/keycloak.service:

    [Unit]
    Description=Keycloak IAM
    After=network.target postgresql.service
    Requires=postgresql.service
    
    [Service]
    Type=simple
    User=keycloak
    Group=keycloak
    WorkingDirectory=/opt/keycloak
    
    ExecStart=/opt/keycloak/bin/kc.sh start --optimized
    
    Restart=on-failure
    RestartSec=5
    
    [Install]
    WantedBy=multi-user.target

    Então basta habilitar e iniciar o serviço com:

    # systemctl enable --now keycloak.service

    Após a instalação e a configuração do proxy reverso, o Keycloak pode ser acessado através da página web. O administrador criado através do comando de bootstrap é temporário, devendo se criar outro usuário administrador e excluir o usuário temporário. Para criar outro usuário administrador, deve-se estar no realm master (único criado por padrão na instalação).

    Após criado, vá na aba de credenciais e adicione uma senha.

    Então vá na aba “Role mapping” e adicione o papel de admin.

    Após logar no novo usuário, exclua o usuário temporário.

    Agora sobre a organização interna do Keycloak. Ele é dividido em realms, que são como domínios isolados. Cada realm tem seus usuários, grupos e configurações. O master, único realm existente por padrão após a instalação, é para gerenciamento do próprio Keycloak e não deve ser utilizado para criar usuários de aplicações. Em vez disso, outro realm deve ser criado.

    Dentro desse novo realm pode-se criar um cliente, que é uma aplicação que irá utilizar o Keycloak como provedor de identidade. Vou utilizar o Nextcloud como exemplo por ser uma aplicação que tem suporte oficial a esse tipo de configuração. Podemos configurar o tipo de autenticação como OpenID Connect ou SAML. Seguindo com o exemplo utilizando OIDC:

    A chave de autorização pode ser deixada desabilitada, porque a autorização é definida pelo servidor Nextcloud: ele determina qual usuário é administrador, qual usuário tem acesso a quais compartilhamentos de arquivos, etc.

    A caixa “Standard Flow” determina o fluxo de autenticação padrão para navegadores web. Para fazer o login, o usuário é redirecionado para fazer login no Keycloak.

    Alternativamente, existe a opção “Direct Access Grants”, em que o login é feito na página do Nextcloud, que envia as credenciais para o Keycloak.

    “Standard Flow” é recomendado porque assim a senha do usuário fica restrita ao Keycloak, enquanto em “Direct Access Grants” a senha passa pela aplicação, o que em muitos casos é indesejado – como por exemplo quando o provedor do serviço e o cliente são organizações diferentes. Além disso, a ideia é sempre minimizar a exposição da senha. Assim, caso a aplicação seja comprometida não significa que a identidade do usuário também vai ser.

    No Standard Flow, o fluxo de autenticação acontece da seguinte forma:

    1. Usuário acessa a página de login do Nextcloud.
    2. Nextcloud o redireciona à página de login do Keycloak.
    3. Usuário faz login no Keycloak.
    4. Keycloak gera um código de autorização e redireciona o usuário de volta ao Nextcloud enviando junto esse código de autorização, indicando que o usuário foi autenticado no Keycloak.
    5. Nextcloud faz uma chamada ao Keycloak, enviando as próprias credenciais de autenticação de cliente (quando habilitado) e devolvendo o código de autorização recebido e solicitando um token.
    6. Keycloak valida a autenticação do Nextcloud e o código de autorização e retorna o token para o Nextcloud.
    7. Nextcloud associa o token a uma sessão e estabelece a sessão do usuário.

    Os passos 5 e 6 podem parecer redundantes após o 3 e 4 mas não são. Essa etapa a mais existe porque o código de autorização passa através de um redirect do Keycloak para o Nextcloud, passando pelo navegador web do usuário. O Nextcloud então no passo 5 faz uma chamada diretamente para o Keycloak, que valida o código de autorização e retorna ao Nextcloud um bearer token que o Nextcloud utiliza como credencial do usuário para estabelecer a sessão.

    O “Implicit Flow” corta essa etapa e devolve ao navegador o token de acesso diretamente, o que agiliza o login mas agora o navegador possui o token.

    As URLs de redirect são geradas pelo plugin de OIDC do Nextcloud após o registro do provedor de identidade, podem ser substituídas depois caso ainda não as tenha.

    Após a criação do cliente, crie o segredo para autenticação da aplicação no Keycloak.

    Agora, deve ser configurado OpenID Connect no Nextcloud. A começar pela instalação do plugin:

    Nas configurações de administração, basta registrar um novo provedor:

    O endpoint de descoberta é /realms/<nome do seu dominio>/.wellknown/openid-configuration.

    Após essa configuração, o Nextcloud exibe a opção de login com o provedor configurado.

    Ao clicar nesse botão, o usuário é levado à página de login do Keycloak.

    Ao fazer o login, o Nextcloud cria o usuário e inicia a sessão.

    Uma funcionalidade interessante do Keycloak é que ele pode também passar à aplicação os grupos aos quais o usuário pertence e, caso a aplicação tenha suporte, ela pode automaticamente provisionar os grupos e atribuir o usuário a eles.

    Isso pode ser vantajoso quando recursos ou permissões na aplicação são concedidos a grupos em vez de contas individuais, de forma que o usuário pode ser criado já com os acessos desejados. No Nextcloud, por exemplo, um compartilhamento de arquivos pode ser feito para um grupo.

    Para configurar isso no Keycloak, deve-se criar um mapeamento de grupos. Configurando apenas para um cliente específico, isso é feito nos detalhes do cliente, na aba “Client scopes”, no escopo dedicado do cliente, nextcloud-oidc-dedicated.

    Basta adicionar um Mapper do tipo “Group Membership” com o nome que a aplicação espera no token. No caso do Nextcloud, o mapeamento foi configurado para groups. Desative a opção “Full group path” para evitar que o nome do grupo seja passado à aplicação como /nome-do-grupo.

    No Nextcloud, o provedor de identidade precisa ter o provisionamento de grupos habilitado e o regex de whitelist especificado para os grupos desejados. Nesse caso, foi configurado para aceitar todos os grupos.

    Feita essa configuração, podemos atribuir um grupo ao usuário existente no Keycloak, e verificar que, após novo login, o grupo também aparece automaticamente no Nextcloud.

  • DMZ virtual no Proxmox com OPNsense

    Por padrão, as máquinas virtuais do Proxmox se conectam a uma bridge ligada à interface física do servidor. Dessa forma, todas as máquinas virtuais aparecem como máquinas reais na rede física onde o servidor está conectado.

    Idealmente, as máquinas virtuais com portas expostas para a internet estariam isoladas da rede principal, mas como o roteador em uso é um roteador de uso doméstico, sem a opção de criação de VLAN ou atribuição de redes diferentes a interfaces diferentes, uma alternativa se apresentou viável: instalar um firewall como máquina virtual no Proxmox e fazer com que as máquinas virtuais se conectem a ele em vez de diretamente na rede física.

    Para o firewall, temos algumas opções de sistema operacional, as mais notáveis de código livre sendo OPNsense e pfSense. O OPNsense é um fork do pfSense, que é um fork do m0n0wall. Eles são baseados no FreeBSD. OPNsense surgiu como um fork do pfSense em grande parte por uma questão de licenciamento, sendo distribuído sob a licença simplificada BSD, e é o firewall utilizado aqui.

    Antes de criar a máquina virtual, precisamos criar pelo menos uma bridge no servidor Proxmox para a LAN do OPNsense, a qual ficarão conectadas as máquinas virtuais. A bridge vmbr0 existente no Proxmox vai ser utilizada para a WAN, conectando o OPNsense à LAN física. Para isso, no Proxmox, selecione seu servidor > System > Network e crie a bridge, dando apenas um nome.

    Após criada, aplique as configurações.

    Alternativamente, pelo terminal do Proxmox, adicione a bridge ao arquivo /etc/network/interfaces:

    auto vmbr1
    iface vmbr1 inet manual
        bridge-ports none
        bridge-stp off
        bridge-fd 0
    # OPNsense LAN
    
    auto vmbr2
    iface vmbr2 inet manual
        bridge-ports none
        bridge-stp off
        bridge-fd 0
    # OPNsense LAN2

    Vale reparar que outras bridges podem ser criadas e atribuídas a uma interface de rede na máquina virtual. Eu decidi criar duas.

    Após editado o arquivo, use o seguinte comando para aplicar a configuração:

    # ifreload -a

    Finalizada a criação das bridges, crie a máquina virtual, adicione as interfaces de rede que desejar, inicie e instale o OPNsense. Ao finalizar, reinicie e atribua às interfaces o uso como WAN ou LAN – e opcionalmente OPT1, OPT2, etc.

    Feito isso, atribua um endereço IP à elas conforme necessário. Nesse caso, a WAN permaneceu em DHCP e a LAN e OPT1 foram configuradas com IP estático – e ativado o servidor DHCP para a rede.

    Então, você já pode alterar a bridge a qual estão conectadas as interfaces de rede das máquinas virtuais, e o OPNsense já deve estar acessível via web através da LAN virtual. No entanto, ele ainda não está acessível através da WAN (a LAN física). Para isso, são necessárias três configurações:

    • Vá em Interfaces > [WAN] e desabilite a caixa “Block private networks”.
    • Vá em Firewall > Settings > Advanced e habilite a caixa “Disable reply-to on WAN rules”.
    • Em Firewall > Rules, crie uma regra para a interface WAN permitindo tráfego de entrada de “WAN net” para o OPNsense.

    Agora, você deve alterar no Proxmox a configuração da interface de rede das máquinas virtuais que desejar para que elas utilizem a bridge correspondente à interface LAN do OPNsense.

    Você vai ver que, ao pingar um IP da sua LAN física a partir de uma máquina virtual conectada ao OPNsense, a máquina virtual vai receber a resposta. Agora, basta criar a regra que vai isolar a rede LAN do OPNsense da sua LAN física.

    No OPNsense, crie uma regra para a LAN, bloqueando todo tráfego de entrada na interface LAN com destino a “WAN net” e coloque essa regra ao topo das regras padrão de permissão de entrada de tráfego na interface LAN.

    Pelo fato de OPNsense ser um firewall do tipo stateful, para garantir que nenhuma conexão já estabelecida se mantenha, vá em Firewall > Diagnostics > States e, na aba Actions, resete a tabela de estado.

    Agora, toda máquina virtual que for configurada no Proxmox e precise ficar isolada da rede LAN física, deve ser conectada à bridge correspondente à LAN do OPNsense – nesse caso, vmbr1.

    Recomendação de segurança: no OPNsense, crie um usuário, inclua ao grupo admin e, após logar nele, desabilite o usuário root.

    Posteriormente, eu vi que existem algumas opções de serviço DHCP. O padrão configurado na linha de comando é o “Dnsmasq DNS & DHCP” e é o mais leve mas parecia não ter a opção de reservas DHCP, então configurei o Kea DHCP, uma implementação mais recente desenvolvida pela Internet Systems Consortium (ISC), para ser usado com as interfaces LAN e OPT1.

    A interface OPT1 foi configurada de forma parecida à LAN mas um pouco mais restrita, com acesso bloqueado tanto à “WAN net” quanto à “LAN net”. A ideia sendo que a LAN vai abrigar os servidores em uso, já relativamente bem configurados e mantidos, enquanto a rede na interface OPT1 vai abrigar máquinas virtuais de teste.

    Outra configuração feita posteriormente: foi criada uma regra no firewall para permitir o acesso da rede WAN às redes LAN e OPT1.

    Adicionalmente, no roteador da rede física, foi configurada uma rota para as redes LAN e OPT1 através do IP do firewall na WAN.

    Dessa forma, conseguimos acessar da rede física as máquinas virtuais nas redes LAN e OPT1 através do IP individual delas, sem necessidade de configuração de encaminhamento de portas para cada uma, enquanto mantendo bloqueado o acesso das redes LAN e OPT1 à WAN.

    Para a interface LAN, foi restringido o acesso à internet, criando grupos de IPs com alias e liberando o acesso a endereços essenciais, como repositórios de pacotes do Ubuntu e CentOS Stream para manter os sistemas atualizados, servidor de VPN para manter o acesso aos serviços web pelo proxy reverso, e acesso à Cloudflare para DNS sobre TLS, de modo a melhorar a segurança sem quebrar nenhum acesso previamente utilizado.

  • Protegendo serviços web com ModSecurity

    Web Application Firewall é um tipo de aplicação que inspeciona as requisições HTTP em busca de ameaças comuns, como injeções de SQL, cross-site scripting (XSS), tentativas de inclusão de arquivos remotos e injeção de comandos, antes de encaminhá-las ao servidor web.

    São tipos de ameaças que costumam ser tratadas no back-end dos sites, mas nem sempre acontece. Eventualmente desenvolvedores esquecem de sanitizar um input em alguma parte do código e vulnerabilidades surgem. Um exemplo disso é a vulnerabilidade por injeção de SQL no Zabbix que foi encontrada no final de 2024.

    Tendo isso em vista, é interessante ter uma camada extra de segurança que verifique cada requisição HTTP. É aí que entra o Web Application Firewall (WAF): ele atua como um proxy reverso + firewall. Recebe a requisição HTTP, inspeciona e, caso ela infrinja alguma regra, impede a conexão. Caso contrário, encaminha a requisição para o servidor web.

    Existem diferentes alternativas de WAF, incluindo serviços em nuvem como o Azure Web Application Firewall. Mas minha infraestrutura já utilizava o nginx como proxy reverso para os meus servidores web, então busquei uma alternativa que fosse gratuita e que usasse poucos recursos de hardware, de forma que coubesse no meu VPS de 1 vCPU e 512 MB de RAM.

    A que melhor se encaixou foi o ModSecurity, um módulo de código aberto originalmente escrito para trabalhar com o Apache, mas que hoje também funciona com o nginx. Para instalar no meu servidor, que roda Debian 12:

    # apt install libnginx-mod-http-modsecurity modsecurity-crs

    O pacote modsecurity-crs é o Core Rule Set da OWASP, um conjunto de regras base utilizado pelo ModSecurity para identificar e bloquear potenciais ameaças.

    Verifique que o módulo está habilitado. Na pasta /etc/nginx/modules-enabled deve haver um softlink como

    50-mod-http-modsecurity.conf -> /usr/share/nginx/modules-available/mod-http-modsecurity.conf

    Em seguida, edite o arquivo de configuração /etc/nginx/modsecurity.conf e configure o seguinte parâmetro:

    SecRuleEngine On

    Edite também o arquivo /etc/nginx/modsecurity_includes.conf, copiando para ele as linhas em /usr/share/modsecurity-crs/owasp-crs.load que começam com “Include”. Essas são o conjunto base de regras da OWASP.

    Seu arquivo deve ficar algo como:

    include modsecurity.conf
    #include /usr/share/modsecurity-crs/owasp-crs.load
    Include /etc/modsecurity/crs/crs-setup.conf
    Include /usr/share/modsecurity-crs/rules/*.conf

    Feito isso, você pode editar os arquivos de configuração dos sites existente para adicionar no topo no bloco server as seguintes linhas:

    modsecurity on;
    modsecurity_rules_file /etc/nginx/modsecurity_includes.conf;

    Teste as configurações e, se tudo estiver ok, reinicie o servidor web:

    # nginx -t
    # systemctl restart nginx

    É isso, o WAF está funcionando.

    Você pode testá-lo fazendo requisições http que ele deve bloquear e verificando tanto o resultado (ele rejeita com resposta 403) quanto os logs:

    # tail -f /var/log/nginx/modsec_audit.log

    Exemplos de requisições para fazer:

    $ curl "https://pid1.com.br/?id=1+UNION+SELECT+1,2,3"
    $ curl "https://pid1.com.br/?q=<script>alert('xss')</script>"
    $ curl "https://pid1.com.br/?page=http://evil.com/shell.txt"
    $ curl "https://pid1.com.br/?cmd=cat+/etc/passwd"

    Você também pode colocar um input como “UNION SELECT” em algum campo do seu site e verificar que ele responde com 403.

    Agora, problemas como falsos positivos podem acontecer. Eu fiquei impossibilitado de publicar ou salvar publicações como rascunho aqui no WordPress, por exemplo, recebendo o erro “Falha ao atualizar. A resposta não é um JSON válido”.

    Para resolver isso, foi necessário coletar as informações do log para criar uma regra que permita esse caso e ignore a regra que causa o bloqueio.

    O log foi o seguinte:

    ModSecurity: Warning. Matched "Operator Pm' with parameter document.cookie document.write .parentnode .innerhtml window.location -moz-binding <!-- --> <![cdata[' against variable ARGS:json.content' (Value: <!-- wp:paragraph -->\x0a<p>teste4</p>\x0a<!-- /wp:paragraph -->\x0a\x0a<!-- wp:paragraph -->\x0a<p> (30 characters omitted)' ) [file "/usr/share/modsecurity-crs/rules/REQUEST-941-APPLICATION-ATTACK-XSS.conf"] [line "232"] [id "941180"] [rev ""] [msg "Node-Validator Blacklist Keywords"] [data "Matched Data: <!-- found within ARGS:json.content: <!-- wp:paragraph -->\x0a<p>teste4</p>\x0a<!-- /wp:paragraph -->\x0a\x0a<!-- wp:paragraph -->\x0a<p></p>\x0a<!-- /wp:paragraph -->"] [severity "2"] [ver "OWASP_CRS/3.3.4"] [maturity "0"] [accuracy "0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-xss"] [tag "paranoia-level/1"] [tag "OWASP_CRS"] [tag "capec/1000/152/242"] [hostname "191.252.110.50"] [uri "/wp-json/wp/v2/posts/385"] [unique_id "176202912980.702618"] [ref "o0,4v13,112t:utf8toUnicode,t:urlDecodeUni,t:htmlEntityDecode,t:jsDecode,t:cssDecode,t:lowercase,t:removeNulls"] ModSecurity: Access denied with code 403 (phase 2). Matched "Operator Ge' with parameter 5' against variable TX:ANOMALY_SCORE' (Value: 5' ) [file "/usr/share/modsecurity-crs/rules/REQUEST-949-BLOCKING-EVALUATION.conf"] [line "81"] [id "949110"] [rev ""] [msg "Inbound Anomaly Score Exceeded (Total Score: 5)"] [data ""] [severity "2"] [ver "OWASP_CRS/3.3.4"] [maturity "0"] [accuracy "0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-generic"] [hostname "191.252.110.50"] [uri "/wp-json/wp/v2/posts/385"] [unique_id "176202912980.702618"] [ref ""]

    Nele, pode-se identificar:

    • A URI: /wp-json/wp/v2/posts/385
    • O ID da regra que estava causando o bloqueio: 941180

    A partir disso, pode-se criar um arquivo de configuração /etc/nginx/modsecurity_custom_exceptions.conf, com a seguinte regra:

    SecRule REQUEST_URI "@beginsWith /wp-json/wp/v2/posts"\
    "id:10001,phase:1,nolog,pass,ctl:ruleRemoveById=941180"

    Esse arquivo deve ser incluído no /etc/nginx/modsecurity_includes.conf – adicione a linha:

    Include modsecurity_custom_exceptions.conf

    A regra é composta da seguinte forma:

    SecRule VARIÁVEIS OPERADOR [AÇÕES]

    Nesse caso,

    • Variável: REQUEST_URI – é a váriável que ele vai verificar para aplicar a ação.
    • Operador: “@beginsWith /wp-json/wp/v2/posts” – o que ele vai verificar na variável.
    • Ações: “id:10001,phase:1,nolog,pass,ctl:ruleRemoveById=941180”

    Entre as ações:

    • id:10001 – ID da regra que você está criando. Deve ser único.
    • phase:1 – indica que a ação deve ocorrer na fase dos cabeçalhos de requisição – quando o ModSecurity recebe o cabeçalho do nginx, antes de receber o corpo da requisição HTTP e aplicar as regras, que seria a phase:2
    • nolog – sem necessidade de registrar esse evento
    • pass – permite a requisição HTTP
    • ctl:ruleRemoveById=941180 – desabilita a regra que causava o bloqueio. Múltiplas ações desse tipo podem ser especificadas na mesma regra.

    Há também no log uma regra de ID 949110, mas ao ver a mensagem associada é possível verificar que ela não é a regra que identifica a ameaça em potencial, apenas a regra que determina um limite de ameaças detectadas. Não desabilite essa regra, isso abriria espaço para outras requisições HTTP que não devem ser recebidas pelo servidor. É preciso analisar o log com atenção e verificar a que mensagens cada regra está associada.

    Esse tipo de ajuste também pode ser feito para outras regras em outras URIs de outros sites para os quais o nginx atua como proxy reverso, permitindo o uso do WAF para diferentes aplicações e sistemas.

    Uma observação importante: a ordem em que as configurações são incluídas no arquivo /etc/nginx/modsecurity_includes.conf é importante, já que as regras são processadas de forma sequencial. Garanta que as exceções são incluídas para serem processadas antes das regras da OWASP.

    Include modsecurity.conf
    Include modsecurity_custom_exceptions.conf
    Include /etc/modsecurity/crs/crs-setup.conf
    Include /usr/share/modsecurity-crs/rules/*.conf

    Para casos em que uploads de arquivos são feitos, como no Nextcloud, considere também ajustar no arquivo /etc/nginx/modsecurity.conf o parâmetro de tamanho máximo do corpo das requisições HTTP, especificado em bytes.

    #SecRequestBodyLimit 13107200
    SecRequestBodyLimit 31457280

    O limite padrão é 12.5 MB, tendo sido ajustado para 30 MB. Idealmente ajustaria para um valor mais alto mas o consumo de memória pelo nginx ultrapassa o limite tolerado pelo systemd-oomd no meu servidor com 512 MB de RAM, levando o systemd-oomd a matar o processo.

  • Configuração do FreeRADIUS para autenticação com Google LDAPS

    Sendo uma alternativa ao ambiente Microsoft, o Google Workspace também conta com um serviço de diretório. O LDAP seguro pode ser usado para autorização e autenticação de usuários. O FreeRADIUS foi usado para implementar autenticação WPA2-Enterprise na rede Wi-Fi, com um detalhe: a autenticação precisava funcionar para 2 domínios de e-mail diferentes, de dois ambientes Google Workspace independentes.

    Enquanto a autenticação com AD no FreeRADIUS é feita através do método de desafio e resposta, MSCHAPv2, o LDAP seguro do Google não implementa esse protocolo e precisa que a senha do usuário seja enviada em texto pleno dentro de um túnel SSL. Isso pode ser feito com a combinação de protocolos EAP-TTLS/PAP. Diferente do EAP-TLS, que exige o par de certificado/chave tanto do cliente quanto do servidor, o EAP-TTLS exige o par apenas do servidor.

    O servidor utilizado foi o Ubuntu 24.04 mas o processo serve também para outras versões. Primeiro passo é criar o cliente LDAP no Google Workspace. No console de administrador, vá em Apps > LDAP > Adicionar Cliente

    Atribua as permissões necessárias para o cliente:

    Em seguida, baixe os certificados e ative o serviço.

    Agora, preparando o servidor FreeRADIUS:

    # apt install freeradius freeradius-ldap

    Diferente do CentOS, o Ubuntu já gera os certificados pro TLS automaticamente no processo de instalação.

    Diferentes clientes podem ser adicionados no arquivo /etc/freeradius/3.0/clients.conf em blocos do tipo:

    client roteador0 {
    	ipaddr = 56.125.2.213
    	secret = senhaNoPost-it
    	require_message_authenticator = yes
    	shortname = rt0
    }

    Transfira o par de certificado/chave baixado do Google Workspace para o servidor, armazenando-os em /etc/freeradius/3.0/certs/google/, onde já é esperado pelo FreeRADIUS nas configurações a se seguir.

    Partindo para os arquivos de configuração, a começar pelo LDAP, fazendo uma cópia do arquivo para cada ambiente Workspace:

    # cp -a /etc/freeradius/3.0/mods-available/{ldap_google,ldap_workspace0}
    # cp -a /etc/freeradius/3.0/mods-available/{ldap_google,ldap_workspace1}

    Edite o arquivo, adicionando ou alterando as linhas:

    ldap ldap_workspace0 {
        identity = 'nomeDeClienteObtidoNoGoogleWorkspace'
        password = 'senhaDeClienteObtidaNoGoogleWorkspace'
        base_dn = 'dc=dominio0,dc=com'
        user {
            filter = "(mail=%{%{Stripped-User-Name}:-%{User-Name}})"
        }
        certificate_file = /caminho/do/cert/cliente/ldap
        private_key_file = /caminho/da/chave/cliente/ldap
    }

    Faça o mesmo para ldap_workspace1. Habilite os módulos com:

    # ln -s /etc/freeradius/3.0/mods-available/ldap_workspace0 /etc/freeradius/3.0/mods-enabled/

    No arquivo /etc/freeradius/3.0/mods-enabled/eap, adicione ou altere as seguintes configurações:

    eap {
      default_eap_type = ttls
      ttls {
        default_eap_type = pap
      }
    }

    Caso tenha alterado os certificados a serem usados, você também vai precisar editar as configurações referentes a isso no bloco de configurações comuns de TLS.

    Você pode comentar outros módulos não utilizados, como TLS, PEAP e MSCHAPv2, deixando apenas as configurações comuns de TLS e o bloco do TTLS.

    O arquivo /etc/freeradius/3.0/sites-enabled/default tem diversas opções, muitas podem (e devem) ser desabilitadas. Edite os blocos authorize e authenticate para que fiquem como abaixo:

    server default {
      authorize {
        filter_username
        preprocess
        eap
        expiration
        logintime
      }
      authenticate {
        eap
      }
    }

    No arquivo /etc/freeradius/3.0/sites-enabled/inner-tunnel, edite os mesmos blocos, adicionando a condicional para os dois domínios:

    server inner-tunnel {
    
      authorize {
        filter_username
    
        if ("%{User-Name}" =~ /@dominio0\.com$/) {
          ldap_workspace0
          update control {
            Auth-Type := ldap_workspace0
          }
        } elsif ("%{User-Name}" =~ /@dominio1\.com$/) {
          ldap_workspace1
          update control {
            Auth-Type := ldap_workspace1
          }
        } else {
          reject
        }
    
        expiration
        logintime
      }
    
      authenticate {
        Auth-Type ldap_workspace0 {
          ldap_workspace0
        }
        Auth-Type ldap_workspace1 {
          ldap_workspace1
        }
        Auth-Type PAP {
          pap
        }
      }
    
    }
    

    Terminando a edição dos arquivos, você deve reiniciar o serviço para que as configurações tenham efeito, garantindo antes que todos os arquivos pertencem ao usuário e grupo freerad.

    # chown -hR freerad:freerad /etc/freeradius
    # systemctl restart freeradius.service

    Caso necessário, você pode testar o FreeRADIUS em modo debug parando o serviço e executando-o manualmente da seguinte forma:

    # freeradius -X

    Uma funcionalidade interessante é a de atribuir uma VLAN específica dependendo da unidade organizacional do usuário no Google Workspace.

    Para isso, basta utilizar blocos desse tipo dentro do bloco de post-auth:

    if (&Client-Shortname == "rt0" && &User-Name =~ /@dominio0\.com$/i) {
    
        if (&control:LDAP-UserDN =~ /ou=RECURSOS HUMANOS/i) {
            update outer.session-state {
                Tunnel-Type := VLAN
                Tunnel-Medium-Type := IEEE-802
                Tunnel-Private-Group-Id := "2"
            }
        }
    }

    Nesse caso, a melhor abordagem foi usar a condicional considerando o cliente do RADIUS e o ambiente Workspace porque os dois ambientes podem ter UOs diferentes e VLANs com IDs diferentes.

    Como se pode ver pelo sinal =~ a checagem da UO não é exata e o mesmo nome poderia ser encontrado em outra UO, o que pode fazer com que a VLAN errada seja atribuída a um usuário.

    Uma forma mais adequada de atribuir uma VLAN seria, ao invés de usar as unidades organizacionais do Workspace para determinar a VLAN diretamente, usar as unidades organizacionais para atribuir usuários a grupos dinâmicos como rh-wifi@dominio0.com que então vão ser verificados pelo FreeRADIUS da seguinte forma:

    if (LDAP-Group == "cn=rh-wifi,ou=Groups,dc=dominio0,dc=com") {
        update outer.session-state {
            Tunnel-Type := VLAN
            Tunnel-Medium-Type := IEEE-802
            Tunnel-Private-Group-Id := "2"
        }
    }
  • Instalação do FreeRADIUS integrado com Active Directory

    RADIUS é um protocolo de rede que oferece gerenciamento centralizado de autorização e autenticação para acesso de usuários a serviços de rede. Muito usado, por exemplo, como uma alternativa mais segura de acesso a uma rede Wi-Fi, onde cada usuário usa suas credenciais para se conectar, em vez de todos compartilharem uma única senha.

    FreeRADIUS é um sistema livre e aberto que implementa esse protocolo e pode ser configurado pra usar diferentes back-ends para autorização e autenticação, um deles é o Active Directory.

    Pra configurar esse sistema, garanta antes que o servidor RADIUS possa encontrar e ingressar no domínio – aqui tratado como exemplo.com:

    • Domínio e o controlador de domínio podem ser encontrados por consulta de DNS e são acessíveis na rede.
    • O arquivo /etc/hosts do servidor deve conter o FQDN especificado, algo como:
    127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
    ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
    192.168.0.10 radius-server.exemplo.com radius-server

    Após isso, instale e configure o Samba, que vai ser usado para ingressar o computador no domínio. A partir daqui, as instruções são válidas para sistemas da família Red Hat, tendo sido usado o CentOS Stream 9.

    # dnf install samba

    Adapte a configuração abaixo para o seu domínio, alterando ou adicionando os seguintes parâmetros no arquivo /etc/samba/smb.conf :

    [global]
        workgroup = EXEMPLO
        security = ads
        winbind use default domain = yes
        realm = EXEMPLO.COM
    
        idmap config * : backend = tdb
        idmap config * : range = 10000-19999
    
        idmap config EXEMPLO : backend = rid
        idmap config EXEMPLO : range = 20000-99999
    

    Remova também o parâmetro a seguir para evitar o risco de conflito na autenticação:

    [global]
        passdb backend = tdbsam

    Verifique se há algum erro na sua configuração com

    # testparm

    Agora, para ingressar o servidor no domínio:

    # net ads join -U Administrator

    Instale o pacote samba-winbind-clients, habilite o serviço winbind e teste a autenticação com ntlm_auth:

    # dnf install samba-winbind-clients
    # systemctl enable --now winbind.service
    # ntlm_auth --request-nt-key --username=daniel --password='senhaqueanoteinoblocodenotas'

    Um output como

    :  (0x0)

    indica sucesso.

    Agora que o servidor já faz parte do domínio e conseguimos autenticar usuários com ntlm_auth, podemos instalar os pacotes do FreeRADIUS para então configurá-lo

    # dnf install freeradius freeradius-utils

    Pra autenticação no AD, vamos usar a combinação de protocolos PEAP/MSCHAPv2.

    Edite a o módulo mschap localizado em /etc/raddb/mods-enabled/mschap para alterar as seguintes configurações

    mschap {
        use_mppe = yes
        require_encryption = yes
        require_strong = yes
        ntlm_auth = "/usr/bin/ntlm_auth --request-nt-key --username=%{%{Stripped-User-Name}:-%{%{User-Name}:-None}} --challenge=%{%{mschap:Challenge}:-00} --nt-response=%{%{mschap:NT-Response}:-00}"
    }

    Edite o módulo eap localizado em /etc/raddb/mods-enabled/eap para alterar a seguinte configuração:

    eap {
        default_eap_type = peap
    }

    Dica: os arquivos de configuração do FreeRADIUS são extensivamente comentados. Isso é ótimo porque ajuda a entender a configuração já na hora. Mas se quiser ver só a configuração, sem os comentários e linhas em branco:

    $ grep -vE '^\s*#|^\s*$' /caminho/para/arquivo.txt

    Na pasta /etc/raddb/certs, execute o arquivo bootstrap para gerar os certificados necessários para o TLS usado no PEAP.

    Adicione o usuário radiusd ao grupo wbpriv para que o FreeRADIUS tenha acesso para ler a resposta do winbind à solicitação de autenticação, através do socket em /var/lib/samba/winbindd_privileged/pipe

    # usermod -aG wbpriv radiusd

    Abra as portas necessárias no firewall:

    # firewall-cmd --permanent --add-port=1812/udp
    # firewall-cmd --permanent --add-port=1813/udp
    # firewall-cmd --reload

    E agora basta iniciar o serviço radiusd:

    # systemctl enable --now radiusd.service

    Você pode testar a autenticação pelo FreeRADIUS com

    radtest -t mschap daniel senhaqueanoteinoblocodenotas localhost 0 testing123

    e configurar outros clientes do FreeRADIUS em /etc/raddb/clients.conf

    Alguns clientes podem não aceitar o certificado gerado com as configurações padrão do FreeRADIUS, então é recomendado ajustar as configurações pra que o certificado seja emitido corretamente para o FQDN do servidor. O Easy RSA também pode ajudar a gerar e manter os certificados.