SQL Injection é uma falha de segurança em aplicativos da web onde os invasores inserem código SQL prejudicial por meio da entrada do usuário. Isso pode permitir que eles acessem dados confidenciais, alterem o conteúdo do banco de dados ou até mesmo assumam o controle do sistema. É importante saber sobre SQL Injection para manter as aplicações web seguras.
SQL Injection (SQLi) é uma vulnerabilidade de segurança que ocorre quando um invasor pode manipular as consultas de banco de dados de um aplicativo da Web inserindo código SQL malicioso nos campos de entrada do usuário. Essas consultas injetadas podem manipular o banco de dados subjacente para recuperar, modificar ou excluir dados confidenciais. Em alguns casos, os invasores podem até aumentar os privilégios, obtendo controle total sobre o banco de dados ou servidor.

Exemplo do mundo real:
Em 2019, a violação de dados da Capital One ocorreu devido a um aplicativo da web configurado incorretamente que permitiu que um invasor explorasse uma vulnerabilidade de injeção de SQL. Isso resultou no vazamento de dados pessoais de mais de 100 milhões de clientes, incluindo nomes, endereços e pontuações de crédito.
Nível de segurança de injeção SQL
DVWA fornece quatro níveis de segurança para SQL Injection para ajudar os alunos a ver como diferentes proteções afetam os ataques:
1. Baixa segurança
O aplicativo pega sua entrada e a coloca diretamente na consulta SQL, sem filtragem.
$id = $_GET['id'];$query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';';- Entrando
':Interrompe a consulta e faz com que o banco de dados gere um erro revelando que é vulnerável. - Entrando
1' OR '1'='1:Faz com que a consulta seja sempre verdadeira para que todos os usuários sejam retornados. - Entrando
1' UNION SELECT user password FROM users--:Junta-se a outra consulta para buscar dados ocultos, como nomes de usuário e senhas.
2. Segurança Média
O aplicativo aplica higienização básica de entrada usando funções comoaddslashes()escapar'.
$id = addslashes($_GET['id']);$query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';';Como pode ser Ataque:
Um simples'injeção não funcionará mais (porque se torna').
Mas os invasores ainda podem ignorar o uso da injeção numérica (já que os números não precisam de aspas).
Exemplo:
como converter string em inteiro java
1 OR 1=1Isso ainda retorna todos os registros.
3. Alta segurança
O aplicativo usa instruções preparadas (consultas parametrizadas) para lidar com segurança com a entrada do usuário.
$stmt = $pdo->prepare('SELECT first_name last_name FROM users WHERE user_id = ?');$stmt->execute([$id]);Ataque:
Tentativas como' OR 1=1ouUNION SELECTnão funciona mais.
A consulta trata todas as entradas como dados e não como código SQL.
Tipos de injeção SQL
Existem diferentes tipos de injeção SQL
1. Injeção SQL baseada em erros
A injeção de SQL baseada em erros é um tipo de injeção de SQL em banda em que um invasor faz com que o banco de dados gere intencionalmente uma mensagem de erro. O invasor então analisa essa mensagem de erro para obter informações valiosas sobre a estrutura do banco de dados, como nomes de tabelas e nomes de colunas, que podem ser usados para criar ataques mais precisos.
Como funciona
Este ataque tem como alvo aplicativos que revelam erros brutos de banco de dados em vez de mostrar mensagens genéricas. Ao injetar informações maliciosas que quebram a sintaxe SQL, os invasores acionam esses erros e obtêm pistas valiosas sobre a estrutura do banco de dados.
classificar matriz java
- Identifique uma entrada vulnerável: O invasor encontra um campo de entrada como uma barra de pesquisa ou um parâmetro de URL que interage diretamente com o banco de dados sem a devida limpeza de entrada.
- Injetar uma carga maliciosa: O invasor injeta um caractere especial (como uma aspa simples
') ou uma função conhecida por causar um erro no banco de dados. - Analise o erro: O banco de dados incapaz de processar a consulta malformada retorna uma mensagem de erro detalhada. Esta mensagem pode revelar informações cruciais como:
- O sistema de banco de dados (por exemplo, MySQL Oracle SQL Server).
- A versão do banco de dados.
- A consulta SQL completa sendo executada.
- Erros de sintaxe específicos que podem ser usados para entender nomes de tabelas ou colunas.
- Refine o ataque: Usando as informações coletadas da mensagem de erro, o invasor pode refinar sua carga para extrair mais dados, como nomes de usuário e senhas.
Exemplo:
Etapa 1: configure seu ambiente
- Inicie o DVWA. Normalmente é acessado navegando para um URL como
http://localhost/dvwano seu navegador.
- Faça login no DVWA com as credenciais padrão:
admin/password.
- Vá para a guia Segurança DVWA e defina o nível de segurança como baixo. Isso garantirá que as vulnerabilidades sejam fáceis de explorar.
Etapa 2: Identifique a vulnerabilidade
A página SQL Injection possui uma caixa de entrada simples onde você pode inserir um ID de usuário. A consulta de back-end é provavelmente algo comoSELECT * FROM users WHERE id = 'user_input'
- Insira um ID válido como
1na caixa de entrada e clique em 'Enviar'. Você deverá ver os detalhes do usuário com ID 1.
Fonte de injeção SQL
PHP $id = $_REQUEST[ 'id' ]; switch ($_DVWA['SQLI_DB']) { case MYSQL: // Check database $query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';'; $result = mysqli_query($GLOBALS['___mysqli_ston'] $query ) or die( ''
. ((is_object($GLOBALS['___mysqli_ston'])) ? mysqli_error($GLOBALS['___mysqli_ston']) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '' ); // Get results while( $row = mysqli_fetch_assoc( $result ) ) { // Get values $first = $row['first_name']; $last = $row['last_name']; // Feedback for end user echo 'ID:
{$id}
First name: {$first}
Surname: {$last}'; } mysqli_close($GLOBALS['___mysqli_ston']); break; case SQLITE: global $sqlite_db_connection; #$sqlite_db_connection = new SQLite3($_DVWA['SQLITE_DB']); #$sqlite_db_connection->enableExceptions(true); $query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';'; #print $query; try { $results = $sqlite_db_connection->query($query); } catch (Exception $e) { echo 'Caught exception: ' . $e->getMessage(); exit(); } if ($results) { while ($row = $results->fetchArray()) { // Get values $first = $row['first_name']; $last = $row['last_name']; // Feedback for end user echo 'ID:
{$id}
First name: {$first}
Surname: {$last}'; } } else { echo 'Error in fetch '.$sqlite_db->lastErrorMsg(); } break; } } ode ?> - Agora tente quebrar a consulta. Insira uma única cotação
'na caixa de entrada e envie.
A consulta se torna:
SELECT * FROM users WHERE id = ''';Aqui o banco de dados vê uma cotação extra e não sabe como completar a consulta.
comando zip no linux
Em vez de mostrar os detalhes do usuário, o aplicativo retornará um erro SQL (algo como 'Você tem um erro na sintaxe SQL…')
Isso é chamado de injeção SQL baseada em erro porque:
- O invasor envia entrada inválida (
') - O banco de dados gera um erro
- Esse erro vaza informações úteis sobre o banco de dados (como tipo de banco de dados, número de estrutura de colunas, etc.)
2. Injeção SQL baseada em união
SQL Injection baseada em união é uma técnica em que os invasores usam oUNIONoperador para combinar os resultados de dois ou maisSELECTinstruções em um único conjunto de resultados. Isso pode permitir que eles extraiam informações de outras tabelas do banco de dados. OUNIONoperador só pode ser usado se:
- Ambas as consultas têm o mesmo número de colunas
- As colunas têm tipos de dados semelhantes
- As colunas estão na mesma ordem
Operador UNIÃO : OUNIONoperador é usado para combinar o conjunto de resultados de dois ou maisSELECTdeclarações.
- Cada
SELECTdeclaração dentroUNIONdeve ter o mesmo número de colunas - As colunas devem ter tipos de dados semelhantes
- As colunas devem estar na mesma ordem
SELECT column_name(s) FROM table1UNIONSELECT column_name(s) FROM table2Exemplo:
Etapa 1: Primeiramente temos que encontrar o número de colunas da tabela existente no site para injetar SQL Injection baseado em UNION:
A página SQL Injection possui uma caixa de entrada simples onde você pode inserir um ID de usuário. A consulta de back-end é provavelmente algo como
SELECT * FROM users WHERE id = 'user_input'Agora tente quebrar a consulta. Insira uma única cotação'na caixa de entrada e envie.
Se o aplicativo estiver vulnerável, você receberá uma mensagem de erro detalhada. Pode ser algo como:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''' at line 1
Etapa 2: Use oUNIONPalavra-chave para descobrir o número de colunas
Para usar oUNIONpalavra-chave (uma próxima etapa comum), você precisa saber o número de colunas na consulta original. Você pode descobrir isso usando oORDER BYcláusula
comando arp-a
- Tente classificar os resultados por coluna
1:1 ORDER BY 1.
- Enviar. Deveria funcionar.
Fonte de injeção SQL
PHP if( isset( $_REQUEST[ 'Submit' ] ) ) { // Get input $id = $_REQUEST[ 'id' ]; switch ($_DVWA['SQLI_DB']) { case MYSQL: // Check database $query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';'; $result = mysqli_query($GLOBALS['___mysqli_ston'] $query ) or die( ''
. ((is_object($GLOBALS['___mysqli_ston'])) ? mysqli_error($GLOBALS['___mysqli_ston']) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '' ); // Get results while( $row = mysqli_fetch_assoc( $result ) ) { // Get values $first = $row['first_name']; $last = $row['last_name']; // Feedback for end user echo 'ID:
{$id}
First name: {$first}
Surname: {$last}'; } mysqli_close($GLOBALS['___mysqli_ston']); break; case SQLITE: global $sqlite_db_connection; #$sqlite_db_connection = new SQLite3($_DVWA['SQLITE_DB']); #$sqlite_db_connection->enableExceptions(true); $query = 'SELECT first_name last_name FROM users WHERE user_id = '$id';'; #print $query; try { $results = $sqlite_db_connection->query($query); } catch (Exception $e) { echo 'Caught exception: ' . $e->getMessage(); exit(); } if ($results) { while ($row = $results->fetchArray()) { // Get values $first = $row['first_name']; $last = $row['last_name']; // Feedback for end user echo 'ID:
{$id}
First name: {$first}
Surname: {$last}'; } } else { echo 'Error in fetch '.$sqlite_db->lastErrorMsg(); } break; } } ?> - Aumente o número:
1 ORDER BY 2. Enviar. Deveria funcionar.
- Continue incrementando até obter um erro. Por exemplo
1 ORDER BY 4pode lhe dar:Unknown column '4' in 'order clause' - Isso significa que a consulta possui 3 colunas.
3. Injeção SQL baseada em cegos
Injeção cega de SQL ocorre quando os invasores não conseguem ver os resultados da consulta diretamente na página da web. Em vez disso, eles inferem informações a partir de mudanças sutis no comportamento ou no tempo de resposta do aplicativo. Embora mais lento e tedioso que o SQLi clássico, ele pode ser igualmente eficaz.
Em vez de recuperar os dados, o invasor infere informações observando o comportamento da página web. Isso normalmente é feito de duas maneiras:
- SQLi cego baseado em booleano: O invasor injeta uma consulta SQL que retorna um verdadeiro ou falso resultado. A resposta do aplicativo Web muda com base no fato de a consulta ser verdadeira ou falsa. Por exemplo, a página pode mostrar uma mensagem diferente ou renderizar um layout diferente.
- SQLi cego baseado em tempo: O invasor injeta uma consulta SQL que faz com que o banco de dados execute uma ação demorada (como um
SLEEP()função) se uma condição for atendida. O invasor observa o tempo que a página leva para carregar para determinar se a condição injetada era verdadeira ou falsa.
Exemplo:
Imagine uma página de login onde você insere um nome de usuário e uma senha. O aplicativo constrói uma consulta SQL como esta:
SELECT * FROM users WHERE username = 'user_input' AND password = 'password_input'Uma injeção cega de SQL envolveria a manipulação douser_inputcampo para fazer uma pergunta ao banco de dados.
Em vez de obter uma resposta direta, o invasor pode tentar algo assim:
user_input = 'admin' AND 1=1; --Se a página carregar normalmente, o invasor sabe disso1=1é um verdadeiro declaração.
user_input = 'admin' AND 1=2; --Se a página mostrar um erro ou se comportar de maneira diferente, o invasor sabe disso1=2é um falso declaração.
Ao usar uma série dessas perguntas de verdadeiro/falso, um invasor pode adivinhar e extrair informações sistematicamente, um caractere por vez. O processo pode ser automatizado para adivinhar tudo, desde nomes de tabelas até senhas de usuários.
Impacto dos ataques de injeção de SQL
- Acesso não autorizado a dados confidenciais : os invasores podem recuperar informações pessoais, financeiras ou confidenciais armazenadas no banco de dados.
- Problemas de integridade de dados : os invasores podem modificar, excluir ou corromper dados críticos, afetando a funcionalidade do aplicativo.
- Escalação de privilégios : os invasores podem ignorar os mecanismos de autenticação e obter privilégios administrativos.
- Tempo de inatividade do serviço : a injeção de SQL pode sobrecarregar o servidor, causando degradação do desempenho ou falhas no sistema.
- Danos à reputação : Um ataque bem-sucedido pode prejudicar gravemente a reputação de uma organização, levando à perda de confiança do cliente.
Prevenindo ataques de injeção de SQL
Existem várias práticas recomendadas para evitar ataques de injeção de SQL:
1. Use instruções preparadas e consultas parametrizadas
Instruções preparadas e consultas parametrizadas garantem que as entradas do usuário sejam tratadas como dados e não como parte da consulta SQL. Essa abordagem elimina o risco de injeção de SQL.
Exemplo em PHP (usando MySQLi):
$stmt = $conn->prepare('SELECT * FROM users WHERE username = ? AND password = ?'); $stmt->bind_param('ss' $username $password); $stmt->execute();2. Empregue procedimentos armazenados
Os procedimentos armazenados são consultas SQL predefinidas armazenadas no banco de dados. Esses procedimentos podem ajudar a evitar a injeção de SQL porque não constroem consultas SQL dinamicamente.
herança em c++
Exemplo:
CREATE PROCEDURE GetUserByUsername (IN username VARCHAR(50)) BEGIN SELECT * FROM users WHERE username = username; END;3. Validação de entrada da lista de permissões
Certifique-se de que as entradas do usuário sejam validadas antes de serem usadas em consultas SQL. Permita apenas determinados caracteres e padrões, como entrada alfanumérica para campos como nomes de usuário ou endereços de e-mail.
4. Use estruturas ORM
Estruturas de mapeamento objeto-relacional (ORM) como Hibernar ou Estrutura de entidade pode ajudar a evitar a injeção de SQL, manipulando automaticamente a geração de consultas, evitando a construção dinâmica de consultas.
5. Restringir privilégios de banco de dados
Conceda as permissões mínimas de banco de dados necessárias aos usuários. Certifique-se de que os aplicativos possam executar apenas as ações necessárias (por exemplo, SELECT INSERT) e restringir permissões como DROP TABLE ou ALTER.
6. Tratamento de erros
Configure o banco de dados e o aplicativo para não exibir mensagens de erro detalhadas ao usuário. Em vez disso, registre erros internamente e exiba mensagens de erro genéricas para os usuários finais.