Hoje chega a ser difícil imaginar um tempo que os sites da internet eram principalmente páginas estáticas com informações, que podiam ser buscadas em alguns mecanismos de busca e levavam de uma a outra através de links. Só isso, não sistemas, formulários e outros elementos. O protocolo que usamos quando acessamos sites na web é o HTTP, hyper text transfer protocol, ou protocolo de transferência de hiper-texto.
Hiper texto é texto com links que levam a outros textos. Esse protocolo foi criado para esse propósito, simplesmente transferir grandes páginas estáticas de texto com formatação e links para outras páginas com mais informação. A internet surgiu como uma ferramenta de divulgação de informações, era vista como uma grande biblioteca, em que você podia subir informações usando o verbo HTTP PUT, podia ler informações usando o GET, alterar informações usando o POST, e por aí vai.
A ideia é sim interessante e, de fato, hoje é implementada por alguns sites como a Wikipédia o google academia e outros. Ninguém mais tem enciclopédia em casa, como era quase padrão nos anos 80. Mas, no início dos anos 90, mais precisamente em 1993, alguns pesquisadores NCSA, um laboratório acadêmico americano, bolaram uma forma de chamar linhas de comando no meio do processamento da requisição web.
Fizeram isso para permitir otimizar algumas atividades na lista de email deles. Chamaram isso de CGI, Common gateway interface, e essa alteração simples mudou tudo. Rapidamente desenvolvedores começaram a criar aplicativos que poderiam ser usados via web, um pouco depois, em 1994, Rasmus Lerdorf criou o PHP, que é um conjunto de aplicativos CGI que permitia que aplicativos web fossem desenvolvidos junto com o código HTML, de forma muito simples.
HTML significa hipertexto mark-up language, ou seja, a linguagem em que as páginas de hiper-texto, com links, são montadas. Algumas pessoas não gostam de considerar HTML como linguagem de programação, visto que é realmente bastante simples, mas, do ponto de vista técnico é sim uma linguagem. Você escreve um arquivo como se fosse HTML simples, estático, mas, no meio dele, inclui comandos próprios que são executados pelo core do PHP e permitem tornar tais páginas dinâmicas de forma muito simples.
Ele criou a primeira das muitas linguagens que usam como base o HTML, com trechos de código script dentro, e que foram responsáveis pela popularização de aplicações web. Logo outras seguiram, tais como o ASP, active server pages da Microsoft. A Sun criou o JSP, java server pages, tudo isso com base no PHP.
E isso ainda é uma tendência hoje em dia, como React e Vue seguindo essa linha até no cliente. Repare que um código que monta comandos para outros sistemas está na origem dos programas web. O script PHP nada mais é que código que monta comandos em HTML para o navegador, sobre como montar a página web.
Mas não para aí, na hora de acessar o banco de dados, essas linguagens tipicamente montavam comandos SQL e os enviavam para o servidor de banco de dados. Com tantos sistemas montando comandos para outros sistemas, era de se esperar que uma vulnerabilidade que explora exatamente isso fosse algo danoso. Não se esqueça de curtir o vídeo e se inscrever na página.
Clique no sininho para ser avisado de novos vídeos. O que são ataques de injeção? Os ataques de injeção são classificados pelo OWASP como o principal risco ou a principal vulnerabilidade de aplicações web.
OWASP é a sigla para Open Web Application Security Project, ou projeto aberto de segurança de aplicações web, falamos mais sobre eles no vídeo sobre classificação de vulnerabilidades. Um ataque de injeção, ou injection, acontece quando uma aplicação monta comandos para outra aplicação usando informações enviadas pelo usuário. Esse tipo de construção, um código que monta comandos para outro sistema usando informações vindas do usuário, é muito comum como vimos, e não tem perigo se for feito da forma correta.
Porém, caso o programador não tome o devido cuidado no processo de montagem do comando, pode acontecer desse código permitir, indevidamente, que uma informação do usuário montada maliciosamente gere um comando para o outro sistema totalmente diferente da lógica original pretendida e isso leve a quebra de confidencialidade, integridade, disponibilidade ou algum outro aspecto de segurança do sistema. São dois os principais ataques de injection: SQL Injection e Script code injection. O SQL Injection ocorre quando o usuário consegue incluir comandos maliciosos dentro dos comandos criados pela aplicação para acessar o banco de dados e o Script code injection ocorre quando o usuário consegue incluir comandos maliciosos dentro do código HTML que será lido por um navegador.
Existem diversos outros ataques de injection, DOM injection, LDAP injection, system code injection, e outros, mas são casos menos comums. Para entender esses ataques, é importante entender um pouco o que é uma aplicação web. Uma aplicação web consiste em, geralmente, três elementos.
Um banco de dados, onde as informações do sistema são armazenadas. Um servidor de aplicações web, onde o código principal da aplicação vai receber as requisições e preparar as respostas. Um cliente que é seu navegador, chrome, Edge, Firefox, etc.
Uma forma excelente de entender como funciona uma aplicação web é usar um proxy de depuração como o telerik fiddler. Trata-se de um software gratuito, você pode baixar, instalar e usar sem problemas. Ao rodar o fiddler ele vai, basicamente, listar para você todas as requisições e respostas que estão sendo feitas na sua máquina por todos os navegadores abertos.
Se você rodar o fiddler agora, vai ver o navegador fazendo requisições para partes desse vídeo, vai ver quaisquer outros navegadores que estejam abertos e por aí vai. Ao fornecer o endereço do site, o seu navegador gera uma requisição HTTP ao site, um comando GET endereço do site ou página buscada. Essa requisição HTTP chega ao servidor web e, conforme o endereço e demais dados da requisição, irá chamar uma função apropriada do sistema para tratar tal requisição.
Essa função vai montar uma resposta HTTP, que, além de várias outras informações, contém o código HTML para ser montado no navegador do sistema. Por exemplo aqui, fiz uma requisição para uma página web, a requisição é um texto puro que, na primeira linha tem um comando GET nome da página e mais alguns elementos chamados headers com outras informações. Vamos falar mais desses outros elementos quando estivermos falando do ataque broken authentication.
O sistema web montou para mim uma resposta HTTP, que também é um texto claro que contém um código de resposta, alguns headers parecidos com os enviados na requisição e um monte de código HTML, que é a informação para o meu navegador montar minha página web. Algumas páginas web tem um formulário, onde o usuário pode fornecer alguns dados ao sistema. Quando ele clica no botão de “ok” ou “submit” do formulário, o navegador gera uma requisição HTTP um pouco diferente, chamada POST, em que, além de solicitar uma página da mesma forma que o GET, também envia as informações que o usuário digitou.
Veja aqui, a requisição POST, além da página alvo e dos headers, tal como o comando GET, tem, no final as informações do meu formulário, o que digitei no login e o que digitei na senha. Repare que a resposta é parecida, também um código de erro ou sucesso, headers e o código HTML da página. Quando o servidor vai tratar essa nova requisição HTTP que tem dados do usuário, ele envia esses dados para uma função do sistema encarregada de tratar aquela página pedida pela requisição POST, passando os dados que o usuário digitou.
Muitas vezes tal função vai montar um comando SQL para armazenar ou verificar informações com base nos dados enviados pelo usuário. Por exemplo, na nossa aplicação de teste, a tela de login é um formulário web que vai gerar uma requisição HTTP POST. Quando o usuário vai logar, ele preenche o login, preenche a senha e clica em “ok”.
O navegador vai gerar então o POST contendo o que o usuário digitou no login e na senha. Suponha que o código no servidor que vai fazer esse login é algo como o indicado na tela. O código em ASP abre a conexão com o banco de dados, daí monta um comando SQL.
SELECT * FROM usuários WHERE login=’ e coloca aqui o que o usuário digitou no campo login, depois ’ AND senha=’ e coloca aqui o que o usuário digitou no campo senha ’ Esse comando pede que o servidor do banco de dados pegue todos os dados, da tabela usuários, ou seja, existe uma tabela nesse banco de dados com os dados dos usuários do sistema, onde o login é igual a esse e a senha igual a essa. Se o usuário digitou um login e senha corretos, esse comando SQL irá retornar o registro daquele usuário, todas as informações do usuário naquela tabela. Mas, se ele digitar ou o login errado ou a senha errada, vai retornar vazio, porque nenhum usuário na tabela usuários corresponde ao filtro indicado.
O if logo a seguir verifica que se for fim de arquivo, eof end of file, significa que não retornou nenhuma informação e, portanto, ou o login está errado ou a senha está errada. Então o código retorna erro 403, acesso negado na resposta. Ou seja, em tese, esse código funciona adequadamente.
Por exemplo, digitei login admin com a senha admin, o comando ficou: SELET * , retorna tudo, FROM usuários, da tabela usuário, WHERE login=`admin` AND senha=`admin`, onde login for admin e senha for admin. Então retornou o registro do admin e tudo funcionou. Se eu digitar uma senha diferente, nenhum registro vai bater e serei recusado.
Mas vamos imaginar que o usuário maliciosamente, digita no campo login algo como ‘ or 1=1 -- e nada no campo da senha. Isso vai ser enviado na requisição http e o código vai montar o comando SQL, só que agora o comando vai ficar: SELEC *, retorna tudo, FROM usuários, da tabela usuário, WHERE login= ``, lembra, havia um a abertura do plic na montagem do comando e outro no dado de login digitado pelo usuário, então busca um login vazio, OR 1=1 --, ou 1 é igual a 1 e, -- significa comentário em SQL, portanto, ignore todo o resto a partir daqui. Pois bem, quais registros da tabela vão bater com esse filtro?
Nenhum login deve ser vazio, mas 1 é sempre igual a 1, como é uma coisa ou outra, esse filtro vai passar para todos os registros da tabela. Vai retornar todos os registros e o sistema vai seguir funcionando com o primeiro usuário que tiver na tabela. Ou seja, sem saber nem o login e senha de nenhum usuário, você logou no sistema como um usuário qualquer.
Pior que, geralmente, o primeiro usuário ainda é o administrador. Repare que a montagem do comando SQL, o fato do programa não tomar cuidado, leva a essa falha. Tente você mesmo.
Se você montou a máquina DVWA conforme expliquei nesse vídeo, vamos testar isso lá. O DVWA não tem fragilidade de SQL Injection no login, mas tem uma função aqui a esquerda, SQL Injection. Lógico, esse formulário possui tal fragilidade.
Vamos experimentar? Veja nesses links outros tipos que você pode testar. Mas repare que esse exemplo simples é só o começo.
Basta uma falha dessa para podermos baixar todo o banco de dados usando técnicas como blind SQL injection, em que o tempo que o sistema leva para responder um comando pode ser usado para extrair informações, veja esse vídeo sobre isso. Existem outras formas de SQL Injection também, como SQL injection refletido, em que a informação originalmente é armazenada no banco de dados e, posteriormente ao ser usada em outra parte do sistema, ela leva ao SQL Injection. O script code injection tem mecânica similar, mas vamos explicar com detalhes no vídeo sobre XSS, visto que os dois estão sempre ligados.
E outros tipos de ataque de injeção são menos comuns, mas seguem a mesma lógica. Nos primórdios na internet, no final dos anos 90, início dos anos 2000, havia uma enorme quantidade de programas com essa fragilidade. Quando eu comecei a atuar profissionalmente como analista de segurança de sistemas, era raro não encontrar múltiplos SQL Injections em toda e qualquer aplicação web que eu ia avaliar.
A coisa era tão absurda que haviam livros ensinando como programa em ASP, e os códigos desses livros eram suscetíveis a SQL Injection. Isso em vários livros sobre ASP, alguns da própria Microsoft. Durante um tempo isso ficou até ligado, como se o SQL Injection fosse uma fragilidade do código ASP.
Mas isso não é verdade, qualquer linguagem está sucetivel, PHP, Java, visual basic. Nem só aplicações web, mas também aplicações cliente servidor podem sofrer esse tipo de ataque. Felizmente o panorama agora melhorou.
Principalmente porque agora existem diversas plataformas de persistência, tais como hibernate, link, entity framework, e várias outras. Essas plataformas cuidam de toda a conexão com o banco de dados e, dessa forma, evitam esse tipo de problemas. Além disso, os programadores hoje, depois de tantos problemas, já sabem que precisam fazer validação de dados de entrada de forma restrita.
Veja como aqui. E, acima de tudo, precisam usar queries SQL parametrizadas. Os comandos SQL montados precisam ser feitos via parâmetros.
Por exemplo, em Java, deve-se usar PreparedStatements, em C# SQLCommand. Parameters, em PHP prepare e bindparam, e assim por diante. Repare que, nesse caso, não há concatenação de strings com parâmetros, mas, na verdade o comando contém marcadores que serão substituídos pelos dados por parâmetros passados após.
Note que não é suficiente marcadores de concatenação como algumas linguagens como JavaScript permitem. Isso é o mesmo que concatenar. Tem que ser parâmetros SQL mesmo, porque, dessa forma, o driver do banco de dados sabe que aquilo é uma variável e, mesmo que contenha um plic ou outro caractere, esse faz parte do dado, não do comando SQL.
Com essas medidas, os comandos SQL podem ser montados de forma simples e segura. Infelizmente, sistemas construídos mais antigamente ou sem tais cuidados, costumam ter vários muitos problemas e dar bastante trabalho para reparar. Mas não há outro caminho.
Um sistema com SQL Injection é um perigo não só para si, mas para outros sistemas que compartilhem o banco de dados. Obrigado por assistir nosso vídeo. Comente abaixo se tiver dúvidas ou sugestões de novos vídeos.