Uma grande variedade de ataques baseados em HTTP podem (e devem) ser evitados em seu aplicativo. O OWASP Top 10 é um excelente exemplo de técnicas de ataque que são detectáveis e evitáveis em qualquer aplicativo. Uma infinidade de ferramentas, incluindo análise estática e dinâmica, bem como testes de penetração, podem garantir que essas vulnerabilidades não passem para a produção. Desde que, é claro, esses testes de segurança sejam transferidos para o processo de CI/CD, em vez de deixados como a etapa final antes de acionar o interruptor (ou bits, por assim dizer) que os torna acessíveis aos usuários.
Mesmo que você tenha eliminado todas as vulnerabilidades potenciais encontradas no desenvolvimento, os aplicativos ainda estão em risco. Isso ocorre porque alguns ataques não podem – e por não podem eu realmente quero dizer não podem – ser detectados pelo aplicativo. Na verdade, quando o ataque chega ao aplicativo, já é tarde demais.
Claro que estou falando sobre ataques DDoS na camada de aplicação (HTTP). Você sabe, os vampíricos que exploram o próprio protocolo HTTP para basicamente sugar até a última gota disponível de computação e memória de um aplicativo, de modo a torná-lo inútil para usuários legítimos.
Existem basicamente dois tipos de ataques HTTP DDOS: o rápido e o lento; o flood e o drain.
Um ataque DDoS HTTP baseado em inundação aproveita o fato de que os aplicativos devem aceitar solicitações HTTP e responder a elas. É meio que o truque deles, não é? E é o que eles fazem. E eles fazem isso independentemente da rapidez com que essas solicitações chegam. Mesmo que as solicitações cheguem a uma taxa que esgote os recursos disponíveis para o servidor em minutos – ou segundos – ele tenta responder. Veja, cada aplicativo (na verdade, cada dispositivo, serviço, sistema, etc.) tem um limite superior para o número de conexões TCP que ele pode manter abertas a qualquer momento antes de simplesmente não conseguir abrir mais. Quando esse limite superior é atingido, quaisquer solicitações subsequentes são simplesmente ignoradas. Os usuários vivenciam isso com o status inócuo “Tentando conectar…”, enquanto o navegador ou aplicativo aguarda até que o tempo especificado pelo sistema tenha passado e, então, pede desculpas por não conseguir se conectar.
Esse tipo de ataque pode ocorrer tão rápido (daí a analogia de uma “inundação repentina”) que ultrapassa a capacidade dos sistemas de escalar para atender à demanda. Nem mesmo o dimensionamento automático pode ajudar nesse cenário, pois o tempo necessário para provisionar e iniciar uma nova instância do aplicativo é maior do que o tempo necessário para o ataque remover todos os recursos das instâncias existentes.
O oposto – um ataque de drenagem – realiza a mesma tarefa, mas forçando o aplicativo a manter uma conexão aberta por mais tempo do que o necessário. Ele consegue isso fingindo que está conectado via discagem; enviando algumas gotas de dados do aplicativo por segundo, em vez da taxa na qual ele é realmente capaz de recebê-los. Fazer isso significa que as conexões duram mais e, se você fizer isso com conexões suficientes, basicamente acabará na mesma situação do ataque de inundação: esgotamento de recursos.
Nenhum desses ataques é detectável dentro de um aplicativo. Por que eles estariam? Para o aplicativo, todas essas solicitações são legítimas; são todas solicitações de dados bem-formadas e baseadas em HTTP, às quais ele provavelmente responde milhares de vezes por dia. Não há nenhum sinalizador nos cabeçalhos HTTP ou na carga útil que indique a natureza nefasta das solicitações. O aplicativo é completamente e totalmente cego às intenções maliciosas por trás dessas solicitações porque não tem visibilidade da rede ou do ambiente mais amplo – especificamente da tabela de sessão do servidor que mantém a lista principal de todas as conexões abertas. Vou poupá-lo dos detalhes técnicos e palestras sobre threads, processos e volatilidade de dados em ambientes multithread e apenas ficar com a "nenhuma visibilidade no processamento de outras solicitações".
Basta dizer que o próprio aplicativo não tem como determinar se uma solicitação específica faz parte de um ataque maior (inundação) ou se seu comportamento é inconsistente com suas capacidades conhecidas (drenagem).
O que tem visibilidade em ambos é o proxy localizado a montante (na frente) do aplicativo. Isso ocorre porque o proxy provavelmente está fazendo balanceamento de carga e, portanto, precisa prestar atenção em quantas solicitações estão em processamento e quantas estão chegando, pois precisa enviá-las para um dos aplicativos no cluster (ou pool, se preferir).
Além disso, ele precisa saber para onde enviar a resposta, para que ele saiba sobre o cliente e sua conexão de rede ( normalmente, apenas o endereço IP do cliente é enviado ao aplicativo, nada mais ). Diferentemente do aplicativo, ele tem a visibilidade necessária para detectar ataques de inundação e drenagem – e detê-los antes que eles possam cravar seus dentes vampíricos nos recursos do aplicativo.
É por isso que serviços baseados em proxy, como um WAF (Web Application Firewall) ou mesmo um balanceador de carga avançado, são essenciais nas estratégias de segurança de aplicativos atuais. Porque eles têm a visibilidade e os meios para detectar o comportamento anômalo indicativo de um ataque – e repeli-lo como alho e um vampiro.
E como esses serviços tradicionalmente de “rede” devem necessariamente se tornar parte da arquitetura do aplicativo, parece lógico que uma abordagem DevOps tenderia a expandir suas asas e ser mais inclusiva daqueles serviços que naturalmente gravitam em direção ao aplicativo em primeiro lugar , como segurança e escalabilidade do aplicativo (balanceamento de carga).
Os aplicativos não podem impedir todos os ataques, especialmente aqueles que exigem um nível de visibilidade que simplesmente não está disponível para eles. No entanto, trabalhar em conjunto com serviços afins de aplicativos, como segurança de aplicativos da web e balanceamento de carga, pode fornecer os meios pelos quais um conjunto mais abrangente de ataques pode ser detectado e repelido para garantir menos interrupções e violações.