Perigos da validação client-side (ou Sempre valide client E server side)

14 F Y

Desenvolvo para a web há praticamente 8 anos. Pude ver muita coisa surgindo, tecnologias, conceitos, frameworks, aplicações, serviços… O bom de aprender cedo a desenvolver é que você presta atenção as falhas dos outros para não comete-las em seus projetos. Já vi absurdos completos, como um site em que os dados do login eram enviados via GET, usuário e SENHA, plaintext, na url de destino… Outros erros comuns, que por vezes me deparo são mais mascarados, mas qualquer desenvolvedor com o mínimo de experiência os conhece e deve tentar evitá-los. Um exemplo é SQL Injection… a técnica é conhecida desde sempre, no entanto, grandes portais ainda são vulneráveis a este “ataque” trivial, que qualquer usuário pode realizar. Já vi o site de um jornal importante, de grande circulação, abrindo as pernas para um “‘or 1 = 1’ ” colocados como usuário e senha… Mas o foco deste post não é este tipo de problema. Quero discutir aqui sobre outra fragilidade de aplicações web, ainda mais fácil de tratar do que SQL Injections ou XSS: Confiar na validação client-side.

Muita gente que desenvolve aplicações web atualmente, vem do mundo da programação desktop normal. Ao validar um campo (um textbox por exemplo), basta validar o valor inserido pelo usuário e processar aquele valor normalmente (se for o caso de inserção em banco de dados, vale a pena colocar validação no banco também, tanto para desktop como principalmente para web). Se quiser desabilitar algum campo, apenas desabilite ele na interface gráfica e pronto, o usuário não vai ter acesso à ele (não na prática, com facilidade suficiente). Ao desenvolver para web, assumir isto pode ser fatal para sua aplicação.

Modificar o conteúdo exibido em uma página, ou mesmo alterar os valores enviados via POST são atividades triviais, que um usuário com conhecimentos mínimos de HTML e/ou do protocolo HTTP podem fazer, usando complementos para o Firefox como o Firebug e o TamperData.

Através do Firebug, é muito fácil alterar por exemplo, o valor de um <option>, para enviar o valor que o usuário desejar, ao invés dos valores pré-definidos. Remover um “disabled” de um input checkbox ou radiobutton é trivial. Com a mesma facilidade, podem ser removidas as chamadas às funções javascript que realizam validação client-side. Confiar em validações feitas em javascript já não é algo muito inteligente, pois praticamente qualquer browser tem opções fáceis de desabilitar a execução de tais scripts.

A validação client-side no entanto não deve ser esquecida. Para o usuário honesto, sem intenção de quebrar o sistema ou explorar vulnerabilidades, ela é muito útil, diminuindo o tempo de resposta caso algum dado esteja incorreto (evitando que os dados sejam enviados, processados pelo servidor, verificados como incorretos e só então ser enviada uma mensagem de erro para o cliente corrigir os dados não conformes), melhorando assim a experiência do usuário.

Frameworks como ASP.NET oferecem facilidades para o desenvolvedor no momento de validar tanto client como server side. Os componentes de validação realizam uma validação client-side, no entanto, todas as verificações são novamente realizadas no momento em que os dados chegam no servidor. Caso estes não sejam válidos, Page.IsValid irá retornar false, e cabe ao desenvolvedor realizar uma verificação ao valor desta propriedade antes de usar os dados. No entanto, deve-se escolher corretamente as validações a serem realizadas em cada cenário, caso contrário, ainda assim poderão passar dados que não deveriam.

Se você acredita que isto é muito teórico, não acontece na prática, está enganado. Nestes dias, um amigo meu foi se inscrever em um curso. Eu e outro amigo já haviamos conseguido nos inscrever, mas as inscrições eram gratuitas, e as vagas haviam se esgotado quando este outro amigo tentou. Quando analisamos a página (escrita em ASP puro, não ASP.NET), percebemos que o radiobutton para escolher o curso que ele desejava estava com um disabled. Resolvemos alterar via Firebug (apenas remover o atributo disabled=”disabled” da tag), selecionar o curso e enviar o formulário. Resultado: Inscrição realizada com sucesso, e quando ele foi ao curso, estava o nome dele lá na lista de inscritos… Até certificado ele recebeu, tudo normal.

Num caso destes, teria que ser verificado se ainda existiam vagas no momento em que o servidor recebe a solicitação. Não precisaria nem de Firebug para um sistema que apenas valida client-side receber mais candidatos inscritos do que deveria. Uma página guardada em cache visitada antes do fim das vagas poderia inscrever várias pessoas. Outro cenário possível era se existisse apenas uma vaga aberta, mas 5 usuários tivessem carregado a página de inscrição ainda com esta vaga restante. Todos eles conseguiriam se cadastrar pela falta de uma validação server-side.

Neste caso, o efeito foi inofensivo. Não faltou lugar, comida (ótimo coffee-break por sinal 🙂 ) nem nenhum outro recurso necessário ao bom andamento do curso por causa desta inscrição adicional. No entanto, cenários em que o dano causado pela falta de verificações semelhantes podem ser consideráveis não são difíceis de imaginar.

Fica o recado, SEMPRE valide seus dados server-side para evitar problemas! Apesar do “trabalho” adicional (que varia consideravelmente dependendo da tecnologia que você estiver usando), vale a pena para garantir o comportamento que você ou seu cliente esperam do seu sistema.


Comentários em ASP.NET

4 F Y

Bem pessoal, desculpem pela inatividade dos últimos dias. Esse vai ser um post bem curto, mas que pode esclarecer uma dúvida muito comum, que várias pessoas (alguns dias atrás, eu estava neste grupo…) compartilham.

Para quem é acostumado a escrever código html na mão, é um ato quase automático digitar <!-- --> para escrever um comentário. Comentários em XML também são escritos usando esta tag. Logo, seria natural tentar usar isto para tentar comentar um trecho de código em algum arquivo aspx/ascx. Para completar, ao usar esta tag, seu código finaliza o Build sem erros e vai pro browser. Só então você descobre que não dá pra comentar usando ela.

O problema é que este comentário é “client-side”. Seu browser irá ignorar o que estiver dentro da tag <!-- -->, e o interpretador do Visual Studio também, pois é uma tag válida. As tags de ASP.NET são interpretadas do lado do servidor, e não importa se seu código “<asp:Label ID="naoQueroQueOUsuarioVejaIssoAgora" runat="server">” está dentro ou fora desse tipo de comentários, o analisador, no momento de “criar” a página que será enviada ao cliente, vai ler o conteúdo interno da tag e ainda lançar uma exceção. Confesso que me passei um bom tempo até descobrir como resolver isto.

A solução é usar a marcação de comentários server-side. A maneira de usar é identica ao que já estamos acostumados, só muda a tag. Ao invés de <!-- -->, usa-se <%-- -->. Pronto, pode colocar o que quiser entre essa tag, o código será solenemente ignorado pelo analisador, e nem vai para o browser do seu cliente, ao contrário do comentário client-side, que é enviado e fica a cargo do browser ignorar.

Uma última dica, que serve tanto para o code-behind como para os aspx/ascx, e que aprendi numa visita de André Furtado a uma das reuniões iniciais da célula de estudos CIN.NET, da qual participo, é usar o atalho “CTRL+K+C” para comentar e “CTRL+K+U” para descomentar um trecho de código. Se eu tivesse lembrado disso na primeira vez que precisei comentar um trecho de código aspx, nunca teria tido o problema :p