AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 121292
Accepted
Ravi
Ravi
Asked: 2015-11-17 18:56:34 +0800 CST2015-11-17 18:56:34 +0800 CST 2015-11-17 18:56:34 +0800 CST

Por que o SQL Injection não acontece nesta consulta dentro de um procedimento armazenado?

  • 772

Eu fiz o seguinte procedimento armazenado:

ALTER PROCEDURE usp_actorBirthdays (@nameString nvarchar(100), @actorgender nvarchar(100))
AS
SELECT ActorDOB, ActorName FROM tblActor
WHERE ActorName LIKE '%' + @nameString + '%'
AND ActorGender = @actorgender

Agora, eu tentei fazer algo assim. Talvez eu esteja fazendo isso errado, mas quero ter certeza de que tal procedimento pode impedir qualquer SQL Injection:

EXEC usp_actorBirthdays 'Tom', 'Male; DROP TABLE tblActor'

A imagem abaixo mostra o SQL acima sendo executado no SSMS e os resultados sendo exibidos corretamente ao invés de um erro:

insira a descrição da imagem aqui

A propósito, adicionei essa parte após o ponto e vírgula depois que a consulta foi executada. Depois executei novamente, mas quando verifiquei se a tabela tblActor existe ou não, ela ainda estava lá. Estou fazendo algo errado? Ou isso é realmente à prova de injeção? Acho que o que estou tentando perguntar aqui também é que um procedimento armazenado como este é seguro? Obrigada.

sql-server sql-server-2008
  • 2 2 respostas
  • 3849 Views

2 respostas

  • Voted
  1. Best Answer
    Solomon Rutzky
    2015-11-17T19:00:17+08:002015-11-17T19:00:17+08:00

    Este código funciona corretamente porque é:

    1. Parametrizado, e
    2. Não fazendo nenhum SQL dinâmico

    Para que o SQL Injection funcione, você deve criar uma string de consulta (o que você não está fazendo) e não converter apóstrofos únicos ( ') em apóstrofos com escape ( '') (esses são escapados por meio dos parâmetros de entrada).

    Em sua tentativa de passar um valor "comprometido", a 'Male; DROP TABLE tblActor'string é apenas isso, uma string simples.

    Agora, se você estivesse fazendo algo como:

    DECLARE @SQL NVARCHAR(MAX);
    
    SET @SQL = N'SELECT fields FROM table WHERE field23 = '
              + @InputParam;
    
    EXEC(@SQL);
    

    então isso seria suscetível a SQL Injection porque essa consulta não está no contexto atual pré-analisado; essa consulta é apenas outra string no momento. Portanto, o valor de @InputParampoderia ser '2015-10-31'; SELECT * FROM PlainTextCreditCardInfo;e isso poderia apresentar um problema porque essa consulta seria renderizada e executada como:

    SELECT fields FROM table WHERE field23 = '2015-10-31'; SELECT * FROM PlainTextCreditCardInfo;
    

    Este é um (de vários) motivos principais para usar Stored Procedures: inerentemente mais seguro (bem, contanto que você não contorne essa segurança criando consultas como mostrei acima sem validar os valores de quaisquer parâmetros usados). Porém, se você precisar criar um SQL dinâmico, a maneira preferida é parametrizar isso também usando sp_executesql:

    DECLARE @SQL NVARCHAR(MAX);
    
    SET @SQL = N'SELECT fields FROM table WHERE field23 = @SomeDate_tmp';
    
    EXEC sp_executesql
      @SQL,
      N'SomeDate_tmp DATETIME',
      @SomeDate_tmp = @InputParam;
    

    Usando essa abordagem, alguém tentando passar '2015-10-31'; SELECT * FROM PlainTextCreditCardInfo;para um DATETIMEparâmetro de entrada obteria um erro ao executar o procedimento armazenado. Ou mesmo se o Stored Procedure aceitasse @InputParametercomo NVARCHAR(100), ele teria que converter para a DATETIMEpara poder passar para aquela sp_executesqlchamada. E mesmo que o parâmetro no SQL dinâmico seja um tipo de cadeia de caracteres, entrando no procedimento armazenado em primeiro lugar, qualquer apóstrofo único seria automaticamente escapado para um apóstrofo duplo.

    Existe um tipo de ataque menos conhecido no qual o invasor tenta preencher o campo de entrada com apóstrofos de forma que uma string dentro do procedimento armazenado que seria usada para construir o SQL dinâmico, mas declarada muito pequena, não cabe em tudo e empurra o apóstrofo final e de alguma forma termina com o número correto de apóstrofos para não ser mais "escapado" dentro da string. Isso é chamado SQL Truncation e foi falado em um artigo da revista MSDN intitulado "Novos ataques de truncamento SQL e como evitá-los", de Bala Neerumalla, mas o artigo não está mais online. A edição que contém este artigo — a edição de novembro de 2006 da MSDN Magazine — está disponível apenas como um arquivo de Ajuda do Windows (em formato .chmformato). Se você baixá-lo, pode não abrir devido às configurações de segurança padrão. Se isso acontecer, clique com o botão direito do mouse no arquivo MSDNMagazineNovember2006en-us.chm e selecione "Propriedades". Em uma dessas guias haverá uma opção para "Confiar neste tipo de arquivo" (ou algo parecido) que precisa ser marcada/ativada. Clique no botão "OK" e tente abrir o arquivo .chm novamente.

    Outra variação do ataque de truncamento é, supondo que uma variável local seja usada para armazenar o valor "seguro" fornecido pelo usuário, pois tinha aspas simples dobradas para serem escapadas, para preencher essa variável local e colocar as aspas simples no final. A ideia aqui é que, se a variável local não for dimensionada corretamente, não haverá espaço suficiente no final para a segunda aspa simples, deixe a variável terminando com uma aspa simples que combina com a aspa simples que termina o valor literal no SQL dinâmico, transformando essa aspa simples final em uma aspa simples de escape incorporada, e a string literal no SQL dinâmico termina com a próxima aspa simples que deveria iniciar a próxima string literal. Por exemplo:

    -- Parameters:
    DECLARE @UserID      INT = 37,
            @NewPassword NVARCHAR(15) = N'Any Value ....''',
            @OldPassword NVARCHAR(15) = N';Injected SQL--';
    
    -- Stored Proc:
    DECLARE @SQL NVARCHAR(MAX),
            @NewPassword_fixed NVARCHAR(15) = REPLACE(@NewPassword, N'''', N''''''),
            @OldPassword_fixed NVARCHAR(15) = REPLACE(@OldPassword, N'''', N'''''');
    
    SELECT @NewPassword AS [@NewPassword],
           REPLACE(@NewPassword, N'''', N'''''') AS [REPLACE output],
           @NewPassword_fixed AS [@NewPassword_fixed];
    /*
    @NewPassword          REPLACE output          @NewPassword_fixed
    Any Value ....'       Any Value ....''        Any Value ....'
    */
    
    SELECT @OldPassword AS [@OldPassword],
           REPLACE(@OldPassword, N'''', N'''''') AS [REPLACE output],
           @OldPassword_fixed AS [@OldPassword_fixed];
    /*
    @OldPassword          REPLACE output          @OldPassword_fixed
    ;Injected SQL--       ;Injected SQL--         ;Injected SQL--
    */
    
    SET @SQL = N'UPDATE dbo.TableName SET [Password] = N'''
               + @NewPassword_fixed + N''' WHERE [TableNameID] = '
               + CONVERT(NVARCHAR(10), @UserID) + N' AND [Password] = N'''
               + @OldPassword_fixed + N''';';
    
    SELECT @SQL AS [Injected];
    

    Aqui, o SQL dinâmico a ser executado agora é:

    UPDATE dbo.TableName SET [Password] = N'Any Value ....'' WHERE [TableNameID] = 37 AND [Password] = N';Injected SQL--';
    

    Esse mesmo SQL dinâmico, em um formato mais legível, é:

    UPDATE dbo.TableName SET [Password] = N'Any Value ....'' WHERE [TableNameID] = 37 AND [Password] = N';
    
    Injected SQL--';
    

    Consertar isso é fácil. Basta fazer um dos seguintes:

    1. NÃO USE SQL DINÂMICO A MENOS QUE SEJA ABSOLUTAMENTE NECESSÁRIO! (Estou listando isso primeiro porque realmente deve ser a primeira coisa a considerar).
    2. Dimensione corretamente a variável local (ou seja, deve ter o dobro do tamanho do parâmetro de entrada, apenas no caso de todos os caracteres passados ​​serem aspas simples.
    3. Não use uma variável local para armazenar o valor "fixo"; basta colocar REPLACE()diretamente na criação do Dynamic SQL:

      SET @SQL = N'UPDATE dbo.TableName SET [Password] = N'''
                 + REPLACE(@NewPassword, N'''', N'''''') + N''' WHERE [TableNameID] = '
                 + CONVERT(NVARCHAR(10), @UserID) + N' AND [Password] = N'''
                 + REPLACE(@OldPassword, N'''', N'''''') + N''';';
      
      SELECT @SQL AS [No SQL Injection here];
      

      O SQL dinâmico não está mais comprometido:

      UPDATE dbo.TableName SET [Password] = N'Any Value ....''' WHERE [TableNameID] = 37 AND [Password] = N';Injected SQL--';
      

    Observações sobre o exemplo Trunction acima:

    1. Sim, este é um exemplo muito artificial. Não há muito que se possa fazer em apenas 15 caracteres para injetar. Claro, talvez DELETE tableNameseja destrutivo, mas menos propenso a adicionar um usuário de back-door ou alterar uma senha de administrador.
    2. Este tipo de ataque provavelmente requer conhecimento do código, nomes de tabelas, etc. É menos provável que seja feito por um estranho aleatório / script-kiddie, mas eu trabalhei em um local que foi atacado por um ex-funcionário bastante chateado que sabia de uma vulnerabilidade em uma página da web específica que ninguém mais conhecia. Ou seja, às vezes os invasores têm conhecimento íntimo do sistema.
    3. Claro, é provável que a redefinição da senha de todos seja investigada, o que pode alertar a empresa de que está ocorrendo um ataque, mas ainda pode fornecer tempo suficiente para injetar um usuário back-door ou talvez obter algumas informações secundárias para usar/explorar mais tarde.
    4. Mesmo que esse cenário seja principalmente acadêmico (ou seja, não é provável que aconteça no mundo real), ainda não é impossível.

    Para obter informações mais detalhadas relacionadas à injeção de SQL (cobrindo vários RDBMS e cenários), consulte o seguinte do Open Web Application Security Project (OWASP):
    Testing for SQL Injection

    Resposta relacionada ao Stack Overflow em SQL Injection e SQL Truncation:
    Quão seguro é o T-SQL depois de substituir o caractere de escape?

    • 38
  2. Rob Farley
    2015-11-17T21:56:40+08:002015-11-17T21:56:40+08:00

    A questão simples é que você não está confundindo dados com comandos. Os valores dos parâmetros nunca são tratados como parte do comando e, portanto, nunca são executados.

    Eu escrevi sobre isso em: http://blogs.lobsterpot.com.au/2015/02/10/sql-injection-the-golden-rule/

    • 2

relate perguntas

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Quanto "Padding" coloco em meus índices?

  • Existe um processo do tipo "práticas recomendadas" para os desenvolvedores seguirem para alterações no banco de dados?

  • Como determinar se um Índice é necessário ou necessário

  • Downgrade do SQL Server 2008 para 2005

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve