SQL Server

30 out, 2019

Procedures como defesa à SQL Injection

Publicidade

Hoje, os dados são o bem mais valioso das empresas. O que faz com que qualquer acesso não autorizado ou modificação desses dados impacte todo o sistema de uma empresa. Imagine um sistema que se conecte externamente com um banco de dados sendo usado maliciosamente como ponte para acesso, alteração ou até deleção dos dados privados e importantes para a empresa. Uma técnica de ataque utilizada para sistemas de bancos de dados é o chamado SQL Injection (injeção de SQL).

Nesse ataque, comandos da linguagem SQL são inseridos pelos usuários maliciosos por meio de valores usados como referência e variáveis de entrada para a comparação ou limitação da execução do comando SQL originalmente escrito. Aplicações com campos de texto para utilizá-los como variáveis base para suas consultas ao sistema como login e senha, nomes ou códigos exclusivos de pesquisa, por exemplo, podem ser burlados para finalizar o comando programado e iniciar a execução de outro escrito pelo próprio invasor.

O que ocorre, infelizmente, em muitas aplicações que se conectam com bancos de dados, é a inserção dos comandos SQL dentro do próprio código da aplicação externa, o que permite alteração ou a quebra das regras e tratamentos de valores que esses comandos irão utilizar.

Um exemplo simples, porém prejudicial ao sistema é o seguinte código SQL escrito para ser executado dentro de uma linguagem de programação Back-End:

“SELECT * FROM USERS WHERE EMAIL_USER = ' ”  +  email + “ ' 
  AND PASS_USER = ' “ + pass + ';”

Em um campo de texto em que o usuário pode informar as variáveis de e-mail e senha para ter seus pesquisados, um invasor poderia executar um SQL Injection quebrando a string usada para comparação das variáveis por meio das aspas que delimitam o valor de texto da comparação, e inserindo outra condição que pode, por exemplo, fazer a consulta percorrer todos os usuários inseridos nessa tabela do banco e fornecendo essas informações particulares para o invasor, além de sobrecarregar o sistema.

“SELECT * FROM USERS WHERE EMAIL_USER = 'email@email.com' OR '1' = '1'
  AND PASS_USER = 'myPassword' OR '1' = '1' ;”

Em situações piores, não só um comando de seleção seria executado, em tabelas com dados públicos e privados, mas atualizações, inserções e até deleções dos dados presentes no banco poderiam ser realizadas explorando as falhas de tratamento dos valores externos nos comandos. Algo que muitas aplicações, principalmente aplicações WEB, dos tipos com portais de login de usuário e com busca de dados do banco direto na tela, utilizam erroneamente até hoje. Por exemplo:

DELETE FROM users WHERE id = '' OR 1=1;

Além de alterar as condições de verificação dentro dos comandos SQL, com um ataque de SQL Injection, novos comandos podem ser inseridos na execução, realizando manipulação nos dados ou até mesmo nas estruturas definidas para o banco:

SELECT * FROM USERS WHERE EMAIL_USER = '_' AND PASS_USER = '_';  
DROP TABLE admin;

Claro que para cada tipo de comando e tabela no sistema devemos ter um controle de permissões e acessos nas regras de segurança do sistema gerenciador de banco de dados para impedir que determinados tipos de usuário executem certos comandos como deleção dos dados ou alteração das tabelas. Contudo, para garantir a execução íntegra dos comandos em si, o tratamento, a tipagem e o encapsulamento dos dados usados como variáveis nos comandos SQL compõem a forma primordial para proteção, e até organização no sistema. Isso pode ser feito por meio de Procedures (procedimentos), blocos nomeados de códigos onde podem ser usados comandos e programações da linguagem SQL.

As Procedures são métodos compilados dentro do banco de dados e que permitem a execução de suas programações a partir da chamada de seu nome em aplicações que estejam conectadas ao banco de dados e que tenham as permissões para execução do método.

Procedures nos bancos de dados podem ser execuções vazias ou então retornar valores, sejam eles vindos de variáveis programadas dentro do procedimento ou de seleções de consultas SQL. O grande detalhe que nos permite utilizar esse método para defender nossas aplicações de SQL Injection está nos parâmetros. Além de retornar valores, as Procedures podem receber valores de entrada e garantir a obrigatoriedade ou opcionalidade deles, seus tipos de dados e seus tamanhos.

Com isso, em vez de programar um comando SQL na aplicação externa permitindo a quebra da integridade de seus valores e definições, podemos restringir e encapsular as variáveis usadas nos comandos SQL por meio dos parâmetros da Procedure com a especificação de seus tipos de dados e seus tamanhos aceitáveis, além de ter o código do procedimento armazenado e protegido dentro do banco de dados, evitando modificações externas ou o conhecimento das regras de funcionamento por terceiros.

Assim, convertendo o comando SQL explícito exemplificado antes para o formato de Procedure programada na linguagem T-SQL, utilizada no SGBD SQL Server, sua programação seria feita dessa forma:

CREATE PROCEDURE PRC_PESQUISAR_USUARIO
@email VARCHAR(100),
@senha VARCHAR(50)
AS
BEGIN
  SELECT * FROM USERS WHERE EMAIL_USER = @email AND PASS_USER = @senha;
END;

E nas aplicações que a acessariam, bastaria invocar sua execução:

EXEC PRC_PESQUISAR_USUARIO @email = 'email@mail.com', @senha = 'myPassword';

Dessa forma, o valor usado na comparação seria completamente encapsulado e envolto em considerações unicamente do tipo texto (VARCHAR), nesse exemplo, especificamente com o tamanho máximo de entrada permitido. Nenhum escape das variáveis de comparação e execução dos comandos poderia ser realizado maliciosamente, garantindo que esse quesito de integridade não seja burlado e nem descoberto por aqueles com intenções maliciosas sobre sua aplicação e seu sistema de banco de dados.

— Gabriel Tessarini

#sql #sqlinjection #procedures #hack #hacking #sqlserver #defense