Como prevenir XSS no Django
13 de março de 2023
0 minutos de leituraCross-Site Scripting (XSS) é um tipo de vulnerabilidade que envolve manipular a interação do usuário com um aplicativo web para comprometer o ambiente do navegador. Essas vulnerabilidades podem afetar muitos aplicativos web, inclusive aqueles desenvolvidos com frameworks modernos, como o Django.
Como os ataques de XSS são tão comuns, é essencial proteger seus aplicativos contra eles. Este guia explica como surgem as vulnerabilidades de XSS em aplicativos Django e o que você pode fazer para mitigá-las. Você também vai aprender a usar ferramentas de segurança gratuitas para detectar e corrigir vulnerabilidades de XSS ainda no início do desenvolvimento.
O que é XSS?
O termo XSS surgiu nos primórdios desses ataques, quando o principal objetivo dos invasores era roubar dados entre sites. Mas os ataques de XSS evoluíram e hoje são considerados qualquer ataque que permita aos invasores comprometer dados, tokens e outros elementos do lado do cliente. Um ataque bem-sucedido pode levar a tudo, desde o sequestro de sessões até o controle total de uma conta ou sistema.
Em um ataque de XSS, dados indesejados entram em um aplicativo e são exibidos ao usuário sem validação. Os dados maliciosos enviados na resposta geralmente assumem a forma de JavaScript ou outro código que pode ser executado no navegador do usuário. Quando o navegador executa esse código, ele contorna a política de mesma origem (SOP) e explora o usuário.
Historicamente, os ataques de XSS foram classificados em dois tipos com base na persistência dos dados: refletido e armazenado. Também existe um tipo mais recente de ataque de XSS chamado XSS baseado em DOM.
XSS armazenado
Os ataques de XSS armazenado, às vezes chamados de XSS persistente, ocorrem quando um código malicioso é armazenado no servidor de um aplicativo vulnerável e depois enviado aos usuários sem sanitização (e, por fim, executado pelo navegador do usuário). A carga maliciosa costuma ficar armazenada em bancos de dados, publicações em fóruns, logs ou campos de comentários.

Quando uma vítima acessa o aplicativo afetado, a carga maliciosa é exibida no navegador dela como parte da resposta do servidor. O navegador então executa esses dados e compromete o usuário.
XSS refletido
Os ataques de XSS refletido ocorrem quando a entrada do usuário retornada pelo aplicativo não é salva pelo servidor. Nesse caso, o código não confiável é enviado como parte de um resultado de busca ou mensagem de erro sem a sanitização adequada.

Em geral, o invasor envia a carga maliciosa à vítima disfarçada. Quando a vítima clica nela, o código malicioso é enviado ao aplicativo afetado. O aplicativo responde com o código malicioso, que é executado no navegador da vítima.
XSS baseado em DOM
Os ataques de XSS baseado em DOM ocorrem quando o fluxo de dados maliciosos começa e termina no DOM do navegador. A vulnerabilidade é acionada pela manipulação do DOM do navegador da vítima. A resposta HTTP resultante não muda; ela simplesmente retorna o código do lado do cliente, que então modifica o DOM do navegador de modo a executar a carga maliciosa.
Como prevenir XSS no Django
O Django oferece proteções integradas contra ataques de XSS, incluindo um mecanismo de escape automático para seu mecanismo de templates. Embora ele consiga impedir ataques comuns de XSS, não evita vetores de ataque decorrentes de práticas inadequadas de programação.
Você pode reduzir o risco de ataques de XSS seguindo as práticas recomendadas ao desenvolver seu aplicativo.
Coloque dados dinâmicos entre aspas
Qualquer parte do seu aplicativo que aceite entradas do usuário sem sanitização pode introduzir vulnerabilidades de XSS. Os invasores podem usar esses campos de entrada para injetar código JavaScript arbitrário que não precisa de caracteres HTML.
Por exemplo, o HTML a seguir usa um atributo sem aspas que pode ser modificado para conter manipuladores JavaScript, como onmouseover=alert(1):
É claro que invasores reais não serão tão inofensivos. Em vez disso, vão injetar cargas personalizadas para tirar o máximo proveito dessa oportunidade. Outro exemplo de vulnerabilidade de XSS causada por cargas sem aspas é o uso de variáveis JavaScript para armazenar dados do usuário:
Usar inteiros JavaScript dessa maneira para armazenar um valor fornecido expõe seu aplicativo a ataques de XSS. O mecanismo de escape automático do Django não protege contra isso. Um invasor pode inserir algo tão simples quanto 23 ; payload() e executar código malicioso no navegador de um usuário.
Colocar todos os atributos voltados ao usuário entre aspas duplas ajuda a mitigar essas vulnerabilidades:
Evite literais de template
Se seu código contiver literais de template JavaScript, ele pode estar vulnerável a XSS. Literais de template usam crases em vez de aspas e não escapam os caracteres:
Isso permite que invasores executem código com sucesso ao criar cargas maliciosas com crases. A melhor maneira de evitar esse problema é proibir o uso de literais de template.
Valide URLs de atributos
Muitos atributos HTML, como a href e img src, esperam uma URL e podem ser explorados em ataques de XSS. Os invasores podem simplesmente inserir cargas maliciosas com um URI javascript: para executar o código. O escape de HTML do Django não protege você nesse caso.
Por exemplo, imagine que seu aplicativo permite que os usuários adicionem o URL de seu site pessoal. Usuários mal-intencionados podem usar algo como javascript:payload(XSS) como link. Assim, quando alguém clicar nele, a carga maliciosa será executada.
Para resolver isso, você pode criar uma lista de permissões de protocolos de URL e bloquear todos os demais. Alguns URIs seguros são http:, https:, ftp: e mailto:. Você também pode sanitizar URLs de atributos antes de armazená-las no banco de dados.
Escape dados JavaScript
Inserir dados variáveis diretamente no JavaScript os coloca no contexto de execução. Se o seu programa permitir que os usuários controlem dados inseridos em blocos JavaScript ou manipuladores de eventos, isso poderá levar a ataques de XSS.
Como os invasores podem criar código sem caracteres HTML, confiar no escape de HTML do Django não impedirá ataques de XSS nesses casos.
Para mitigar esse risco, você pode proibir variáveis de template dentro de blocos <script> ou usar a tag de template json_script para ler dados JS:
Não se esqueça de codificar os caracteres dos dados usando o formato \xHH e verificar se o cabeçalho Content-Type do JSON é application/json, e não text/html.
Escape dados CSS
Dados inseridos em tags ou atributos de estilo CSS podem introduzir vulnerabilidades de XSS no seu aplicativo Django. Os invasores podem aproveitar esses dados CSS para acessar o contexto de execução. Isso costuma ser feito pela injeção de código JavaScript em contextos CSS:
A diretiva expression() permite usar instruções JavaScript arbitrárias para avaliar o valor de uma propriedade CSS e deixa seu aplicativo Django vulnerável a ataques de XSS.
Para mitigar esse risco, evite definir valores de parâmetros CSS usando a diretiva expression(). Ao usar instruções JavaScript para definir ou alterar propriedades CSS, tente algo como style.property = x.
Use o filtro safe com moderação
O escape automático do Django funciona bem na maioria dos casos, mas não ajuda se você desativar o escape de HTML com o filtro safe em um template. Quando você marca algo como safe, o Django não faz o escape e exibe os dados sem alterações.
Se seu aplicativo exibir essa consulta sem validar os dados, os invasores poderão usá-la para inserir cargas maliciosas. Use o filtro safe somente quando tiver certeza de que os dados são seguros. Dados fornecidos pelo usuário nunca devem ser marcados como safe.
Restrinja o uso do filtro safeseq
O filtro safeseq indica que o conteúdo a ser exibido é totalmente seguro. Ele pode introduzir cargas de XSS da mesma forma que o filtro safe.
Evite usar esse filtro em dados de sequência. Se precisar usá-lo, use mark_safe(). Assim, durante a revisão de código, você poderá analisar os casos em que algo foi marcado explicitamente como seguro.
Limite o uso de html_safe()
O método html_safe() adiciona o método mágico __html__ à classe fornecida, que retorna uma representação exata em string dessa classe:
O mecanismo de templates do Django não faz escape desses dados, que podem, portanto, causar problemas de XSS. Evite usar html_safe(), a menos que seja necessário. Também evite usar o método mágico __html__ em qualquer classe.
Evite filtros com is_safe=True
Se você registrar um filtro personalizado com is_safe=True, o Django não fará o escape do HTML e marcará como seguro o valor retornado pelo filtro.
Como os dados retornados por esse filtro não passam pelo escape automático do Django, eles podem levar a ataques de XSS. Para ajudar a manter seu aplicativo seguro, evite registrar filtros dessa forma, a menos que tenha certeza de que os dados retornados são seguros.
Limite o uso de mark_safe() e SafeString
O método mark_safe() marca os dados exibidos como seguros e contorna as proteções integradas do Django contra XSS. O uso frequente desse método pode criar um ambiente propício a vulnerabilidades de XSS.
Além disso, quando você usa mark_safe(), ele retorna os dados como SafeString. O Django usa a classe SafeString para determinar quais dados são seguros para exibição. O que acontece, então, quando você usa SafeString diretamente?
Como você deve imaginar, usar diretamente a classe SafeString dessa maneira contorna o escape de HTML do Django e pode levar a XSS. O melhor é limitar o uso tanto de mark_safe() quanto de SafeString.
Evite escrever respostas com HttpResponse
Usar HttpResponse ou classes semelhantes diretamente no seu código contorna o sistema de templates do Django e desativa o escape de HTML.
Isso pode deixar seu programa vulnerável a ataques de XSS, por isso evite escrever respostas dessa maneira. Em vez disso, use o método render() com um template.
Detecte e corrija vulnerabilidades de XSS no Django com a Snyk
Os ataques de XSS estão entre as ameaças mais ativas contra os aplicativos web modernos. Como podem ocorrer de muitas maneiras, é difícil detectar todas as vulnerabilidades de XSS durante a revisão de código. Por isso, é essencial identificar essas vulnerabilidades logo no início do ciclo de vida de desenvolvimento de software (SDLC).
Você pode fazer isso integrando ferramentas de teste específicas ao seu ambiente de desenvolvimento. Vamos usar a Snyk para demonstrar.
A Snyk oferece várias maneiras de testar aplicativos Django, incluindo uma interface web, uma interface de linha de comando, plug-ins para IDEs e APIs. Neste tutorial, você vai usar o plug-in da Snyk para PyCharm e precisará ter o PyCharm instalado para acompanhar (mas a Snyk também oferece suporte a outras IDEs, como o Eclipse e o Visual Studio).
Para usar a Snyk, crie uma conta gratuita e instale o plug-in seguindo o guia de instalação.

Depois de instalar o plug-in, configure o plug-in da Snyk para sua IDE. Você precisa conectar o plug-in à plataforma da Snyk, o que exige a CLI da Snyk. No entanto, não é necessário instalá-la separadamente. Quando você executar uma verificação pela primeira vez, a Snyk fará o download automaticamente.

Você receberá uma solicitação para autenticar a Snyk. Clique em Test code now para acessar a interface web da Snyk.

Clique em Authenticate para confirmar a integração do plug-in.

Após a autenticação, a Snyk começa automaticamente a analisar seu aplicativo Django e exibe os problemas na aba Snyk da sua IDE. Se preferir, você pode iniciar uma análise clicando em Run scan.

A Snyk apresenta informações úteis sobre as vulnerabilidades detectadas, como níveis de gravidade e correções sugeridas.

Você pode corrigir as vulnerabilidades seguindo as atualizações recomendadas pela Snyk. O plug-in sempre recomendará as alterações mínimas necessárias para corrigir seu código.
Conclusão
Os ataques de XSS estão entre os problemas de segurança mais comuns em aplicativos Django. Como podem surgir de diversas fontes e assumir diferentes formas, é difícil evitá-los por completo. No entanto, você pode reduzir o risco de ataques de XSS seguindo estas práticas recomendadas.
Usar as ferramentas certas durante o desenvolvimento também é fundamental. Uma plataforma de segurança dedicada, como o Snyk, pode ajudar você a encontrar e corrigir vulnerabilidades de XSS logo no início do desenvolvimento do seu aplicativo.
Comece a jogar Capture the Flag
Aprenda a resolver desafios de Capture the Flag assistindo à gravação sob demanda do nosso workshop virtual introdutório.
