Entradas e saídas
- 10 minutos
A fraqueza de segurança mais predominante dos aplicativos atuais é uma falha ao processar corretamente os dados recebidos de fontes externas, especialmente a entrada do usuário. Você sempre deve examinar de perto qualquer entrada para verificar se ela foi validada antes de ser usada. Não analisar a entrada do usuário para possíveis ataques pode resultar na perda de dados ou exposição, elevação de privilégio ou até mesmo a execução de código mal-intencionado nos computadores de outros usuários.
A tragédia nessa situação é que esse cenário é um problema fácil de resolver. Nesta unidade, abordamos como tratar dados quando eles são recebidos, quando são exibidos na tela e quando eles são armazenados para uso posterior.
Por que precisamos validar nossa entrada?
Imagine que você esteja criando uma interface para permitir que um usuário crie uma conta em seu site. Nossos dados de perfil incluem um nome, email e um apelido que será exibido para todas as pessoas que visitam o site. E se um novo usuário criar um perfil e inserir um apelido que inclui alguns comandos SQL? Por exemplo, e se um usuário mal-intencionado inserir algo semelhante ao seguinte:
Eve'); DROP TABLE Users;--
Se inserirmos esse valor em um banco de dados, ele poderá alterar a instrução SQL para executar comandos absolutamente indesejados! Este exemplo é conhecido como um ataque de SQL Injection, que é um dos muitos tipos de exploits que podem ocorrer quando você não lida corretamente com a entrada do usuário. O que podemos fazer para corrigir essa situação? Esta unidade ensina quando validar a entrada, como codificar a saída e como criar consultas parametrizadas (o que resolve a exploração acima). Essas são as três técnicas de defesa principais contra entrada mal-intencionada em seus aplicativos.
Quando é necessário validar a entrada?
A resposta é sempre. Você deve validar cada entrada para seu aplicativo. Isso inclui parâmetros na URL, entrada do usuário, dados do banco de dados, dados de uma API e tudo o que é passado em texto claro que um usuário possa manipular. Sempre use uma abordagem de lista de autorização, o que significa que você aceita apenas uma entrada "conhecida como boa", em vez de uma lista de bloqueio (em que você procura especificamente uma entrada incorreta), porque é impossível elaborar uma lista completa de entradas potencialmente perigosas. Faça esse trabalho no lado do servidor, e não no lado do cliente (ou além do lado do cliente), para garantir que suas defesas não possam ser contornadas. Trate TODOS os dados como não confiáveis e você se protegerá da maioria das vulnerabilidades comuns do aplicativo Web.
Se você estiver usando ASP.NET, a estrutura fornecerá um ótimo suporte para validar a entrada no lado do cliente e do servidor.
Se você estiver usando outro framework da web, existem algumas ótimas técnicas para realizar a validação de entrada disponíveis na Folha de Referência de Validação de Entrada OWASP.
Sempre use consultas parametrizadas
Os bancos de dados SQL são normalmente usados para armazenar dados. Por exemplo, o aplicativo pode armazenar informações do perfil do usuário em um banco de dados. Nunca crie consultas SQL embutidas ou outras consultas de banco de dados no seu código usando a entrada bruta do usuário e as envie diretamente para o banco de dados. Esse comportamento resulta em desastre, como vimos anteriormente.
Por exemplo, não crie código como o seguinte exemplo de SQL em linha:
string userName = Request.QueryString["username"]; // receive input from the user BEWARE!
...
string query = "SELECT * FROM [dbo].[users] WHERE userName = '" + userName + "'";
Aqui, concatenamos cadeias de caracteres de texto para criar a consulta, usando a entrada do usuário e gerando uma consulta SQL dinâmica para pesquisar o usuário. Novamente, se um usuário mal-intencionado percebeu que estávamos fazendo isso ou apenas tentou diferentes estilos de entrada para ver se havia uma vulnerabilidade, poderíamos acabar com um grande desastre. Em vez disso, use instruções SQL parametrizadas ou procedimentos armazenados como este:
-- Lookup a user
CREATE PROCEDURE sp_findUser
(
@UserName varchar(50)
)
SELECT * FROM [dbo].[users] WHERE userName = @UserName
Com esse método, você pode invocar o procedimento de seu código com segurança, passando a ele a cadeia de caracteres userName
, sem se preocupar que isso será tratado como parte da instrução SQL.
Sempre codifique sua saída
Qualquer saída que você apresente visualmente ou dentro de um documento sempre deverá ser codificada e ignorada com escape. Isso pode proteger você caso deixe passar algo na fase de limpeza ou caso o código gere algo que possa ser usado de maneira mal-intencionada. Esse princípio de design assegura que tudo seja exibido como saída e não seja acidentalmente interpretado como algo a ser executado, o que é outra técnica de ataque comum conhecida como Cross-Site Scripting (XSS).
Como a prevenção XSS é um requisito comum do aplicativo, essa técnica de segurança é outra área em que ASP.NET faz o trabalho para você. Por padrão, toda a saída já está codificada. Se você estiver usando outro framework web, poderá verificar suas opções de codificação de saída em sites usando a Folha de Referência de Prevenção XSS do OWASP.
Resumo
A limpeza e a validação da entrada são requisitos necessários para garantir que ela seja válida e segura para usar e armazenar. A maioria das estruturas da Web modernas oferece recursos internos que podem automatizar parte desse trabalho. É possível verificar a documentação da sua estrutura favorita e ver que recursos ela oferece. Embora os aplicativos Web sejam o lugar mais comum onde isso acontece, tenha em mente que outros tipos de aplicativos podem ser tão vulneráveis quanto. Não acho que você esteja seguro só porque seu novo aplicativo é um aplicativo da área de trabalho. Você ainda precisará lidar adequadamente com a entrada do usuário para garantir que ninguém use seu aplicativo para corromper seus dados ou manchar a reputação da sua empresa.