É seguro não parametrizar uma consulta SQL quando o parâmetro não é uma string?

113

Em termos de injeção de SQL , eu entendo perfeitamente a necessidade de parametrizar um stringparâmetro; esse é um dos truques mais antigos do livro. Mas quando pode ser justificado não parametrizar um SqlCommand? Algum tipo de dado é considerado "seguro" para não parametrizar?

Por exemplo: Eu não me considero em qualquer lugar perto de um especialista em SQL, mas eu não consigo pensar em nenhum caso em que seria potencialmente vulnerável a injeção SQL para aceitar um boolou um inte apenas concatenar-lo direto para a consulta.

Minha suposição está correta ou isso poderia potencialmente deixar uma grande vulnerabilidade de segurança em meu programa?

Para esclarecimento, esta questão está marcada que é uma linguagem fortemente tipada; quando digo "parâmetro", pense algo como public int Query(int id) .

johnnyRose
fonte
14
Você não obterá o benefício dos planos de consulta em cache se não usar parâmetros; será necessário fazer um plano de consulta separado para cada nova combinação de entradas que você fornecer.
Scott Chamberlain
5
@MatthewWhited Como você saberia que leva menos tempo? Essa situação ocorre em todos os lugares em certos projetos de um desenvolvedor atual e desenvolvedor anterior. Se realmente melhorar a segurança, poste uma resposta. Para esclarecimento, concordo que é melhor parametrizar, obviamente. Mas essa não é realmente minha pergunta.
johnnyRose
7
Consultas parametrizadas são usadas principalmente para desempenho e otimização. A prevenção de injeção de SQL é um efeito colateral.
Salman A de
13
Acho que o OP fez uma pergunta válida. Ele está tentando avaliar o custo / benefício de corrigir um risco potencial. essa equação muda com o potencial desse risco. se houver risco zero, eu também não o faria. Ele fez uma pergunta técnica sobre o potencial, não para um julgamento subjetivo de se você acha que vale o seu tempo. O OP é o único que pode fazer essa chamada.
Senhor Jura-a-lot
10
Para me explicar: sou um dba. Eu aprecio e respeito as melhores práticas e, em um mundo perfeito, todo código seria perfeito. Infelizmente, no mundo em que trabalho, tenho mais problemas para resolver do que tempo para resolvê-los. Isso significa priorização. A reescrita de código IMO que já funciona, é segura e executa em níveis aceitáveis ​​soa como um luxo. (Isso eu não posso pagar)
Senhor Jura-a-lote

Respostas:

101

Acho que é seguro ... tecnicamente , mas é um péssimo hábito de adquirir. Você realmente deseja escrever consultas como esta?

var sqlCommand = new SqlCommand("SELECT * FROM People WHERE IsAlive = " + isAlive + 
" AND FirstName = @firstName");

sqlCommand.Parameters.AddWithValue("firstName", "Rob");

Também o deixa vulnerável na situação em que um tipo muda de um inteiro para uma string (pense no número do funcionário que, apesar do nome - pode conter letras).

Portanto, alteramos o tipo de EmployeeNumber de intpara string, mas esquecemos de atualizar nossas consultas sql. Opa.

Rob
fonte
24
Já podemos parar de usar AddWithValue ? blogs.msmvps.com/jcoehoorn/blog/2014/05/12/…
RemarkLima
5
@RemarkLima Qual é a solução quando você está gerando código dinamicamente que mapeia valores para parâmetros? A postagem do blog não aborda esse cenário. Sim, é uma única linha para definir o tipo de SQL quando é conhecido , mas quando não é, então você tem um problema (ou você tem que recorrer a modelos de anotação com essa informação).
casperOne
1
Então, você está preso, a AddWithValuemenos que tenha um mapeamento de tipos de banco de dados como parte da construção dinâmica da instrução. Eu presumo que você tenha uma lista de colunas de destino e, como parte do dicionário, você pode ter os tipos, se desejar. Caso contrário, apenas pegue o impacto no desempenho. No final das contas, acho que é apenas uma boa informação saber.
RemarkLima de
8
@RemarkLima O ponto é "Podemos parar de usar AddWithValuejá?" deve realmente ser "se você conhece o tipo, então deve evitar o uso AddWithValue.
casperOne
2
Ei, não atire no mensageiro, eu não o escrevi ;-) mas o ponto permanece, e se embutido em seus projetos desde o início, não há razão para você não conhecer o tipo. Melhores práticas e todo aquele jazz :-)
RemarkLima
65

Ao usar uma plataforma fortemente tipado em um computador que você controle (como um servidor web), você pode evitar a injeção de código para consultas com apenas bool, DateTimeou intvalores (e outros numérico). O que é uma preocupação são os problemas de desempenho causados ​​por forçar o sql server a recompilar todas as consultas e por impedi-lo de obter boas estatísticas sobre quais consultas são executadas com que frequência (o que prejudica o gerenciamento do cache).

Mas a parte "em um computador você controla" é importante, porque caso contrário, um usuário pode alterar o comportamento usado pelo sistema para gerar strings a partir desses valores para incluir texto arbitrário.

Também gosto de pensar a longo prazo. O que acontece quando a base de código fortemente tipificada de hoje é portada por meio da tradução automática para a linguagem dinâmica new-hotness e você de repente perde a verificação de tipo, mas ainda não tem todos os testes de unidade corretos para o código dinâmico ?

Realmente, não há um bom motivo para não usar parâmetros de consulta para esses valores. É a maneira certa de fazer isso. Vá em frente e insira os valores de código na string sql quando eles realmente forem constantes, mas caso contrário, por que não usar apenas um parâmetro? Não é como se fosse difícil.

No final das contas, eu não chamaria isso de bug per se, mas sim de cheiro : algo que não chega a ser um bug por si só, mas é uma forte indicação de que os bugs estão próximos ou estarão eventualmente. Um bom código evita deixar odores, e qualquer boa ferramenta de análise estática sinalizará isso.

Acrescentarei que este não é, infelizmente, o tipo de argumento que você pode ganhar diretamente. Parece uma situação em que estar "certo" não é mais suficiente, e pisar na ponta dos pés de seus colegas de trabalho para corrigir esse problema por conta própria provavelmente não promoverá uma boa dinâmica de equipe; em última análise, pode doer mais do que ajuda. Uma abordagem melhor neste caso pode ser promover o uso de uma ferramenta de análise estática. Isso daria legitimidade e credibilidade aos esforços direcionados e voltando e corrigindo o código existente.

Joel Coehoorn
fonte
1
Definitivamente não é um desafio fazê-lo parametrizado. Minha pergunta surgiu porque um colega de trabalho escreveu um monte de consultas concatenando valores inteiros, e eu estava me perguntando se seria uma perda de tempo revisar e corrigir todos eles.
johnnyRose de
2
Acho que a pergunta "Isso é um bug" é o que minha pergunta se resume.
johnnyRose
7
É um "cheiro": algo que por si só não chega a ser um bug, mas indica que provavelmente há bugs nas proximidades. O bom código tenta eliminar odores. Qualquer boa ferramenta de análise estática definitivamente sinalizaria isso.
Joel Coehoorn
1
Gosto do termo "cheiro". Eu teria usado algo como "larva" em vez disso, onde ainda não é exatamente um bug, mas atualizações futuras poderiam pegá-lo em um verme que comerá em seu back-end até que você o esmague ou fumigue. Você certamente não quer que o potencial de código necrótico apareça em um ambiente de produção, e ter algo que não foi desenvolvido com uma certa sutileza pode certamente fazer com que tal esteja presente, como neste caso.
CSS
1
Isso é simplesmente errado. Veja minha resposta, por exemplo, sobre como você ainda pode criar injeção de SQL com DateTimeouint
Kaspars Ozols
53

Em alguns casos, É possível realizar um ataque de injeção de SQL com variáveis ​​não parametrizadas (concatenadas) diferentes de valores de string - consulte este artigo de Jon: http://codeblog.jonskeet.uk/2014/08/08/the-bobbytables -cultura / .

O fato é que, quando ToStringé chamado, algum provedor de cultura customizado pode transformar um parâmetro não string em sua representação string que injeta algum SQL na consulta.

Maciek
fonte
14
Acho que este é o único post que responde à pergunta, que essencialmente é “Como a injeção pode ser possível com ints?”
Arturo Torres Sánchez
3
Porém, se você estiver em posição de injetar código personalizado, como booby trapped, será CultureInfodifícil saber por que você precisaria da injeção de SQL de qualquer maneira.
Martin Smith
mais 1, a única resposta que realmente responde à pergunta
ken2k
@MartinSmith: veja minha resposta, que mostra uma maneira possível de mudar CultureInfo de fora.
user1027167
Se uma pessoa pode escrever esse código no aplicativo, por que ela precisa do SQL Injection?
Reza Aghaei
51

Isso não é seguro, mesmo para tipos que não sejam string. Sempre use parâmetros. Período.

Considere o seguinte exemplo de código:

var utcNow = DateTime.UtcNow;
var sqlCommand = new SqlCommand("SELECT * FROM People WHERE created_on <= '" + utcNow + "'");

À primeira vista, o código parece seguro, mas tudo muda se você fizer algumas alterações nas Configurações Regionais do Windows e adicionar injeção em formato de data abreviada:

Injeção de data e hora

Agora, o texto de comando resultante tem a seguinte aparência:

SELECT * FROM People WHERE created_on <= '26.09.2015' OR '1'<>' 21:21:43'

O mesmo pode ser feito para o inttipo, pois o usuário pode definir o sinal negativo personalizado, que pode ser facilmente alterado para injeção SQL.

Alguém poderia argumentar que a cultura invariável deve ser usada em vez da cultura atual, mas eu tenho visto concatenações de string como esta tantas vezes e é muito fácil perder ao concatenar strings com objetos usando +.

Kaspars Ozols
fonte
10
Quem pode alterar as configurações do servidor? Se uma pessoa pode fazer isso no seu servidor, ela não precisa do SQL Injection para destruir os dados.
Reza Aghaei
5
Esta é a melhor resposta, ela mostra uma maneira que valida a preocupação dos OPs, isso é um bug / falha de segurança. Além do desempenho e da prova de futuro, concatenar data e hora em SQL, por exemplo, não é apenas um cheiro ou uma dívida de tecnologia . @RezaAghaei a pergunta nunca mencionou do lado do servidor, pode ser um aplicativo do Windows com SQLExpress - de qualquer forma, esse não é um critério para a pergunta. Qualquer um poderia dizer quem tem acesso às configurações do servidor para refutar esta excelente resposta, assim como qualquer um poderia dizer o que dizer sobre hospedagem de servidor compartilhado ou um bug do ano 2000. Eu concordo com você, o servidor está sendo bloqueado - não é apenas um pré-requisito.
Jeremy Thompson
2
Você poderia dar um exemplo do que estava dizendo sobre o inttipo?
johnnyRose
1
Eu sei que já se passaram algumas semanas desde que você respondeu isso, mas seria possível editar sua postagem e adicionar um exemplo de como você pode definir um sinal negativo personalizado?
johnnyRose,
23

"SELECT * FROM Table1 WHERE Id =" + intVariable.ToString ()


Segurança
Está tudo bem.
Os invasores não podem injetar nada em sua variável int digitada.

Desempenho
não OK.

É melhor usar parâmetros, então a consulta será compilada uma vez e armazenada em cache para o próximo uso. Da próxima vez, mesmo com valores de parâmetro diferentes, a consulta é armazenada em cache e não precisa ser compilada no servidor de banco de dados.

Estilo de codificação
Má prática.

  • Os parâmetros são mais legíveis
  • Talvez isso o faça se acostumar com consultas sem parâmetros, então talvez você tenha cometido um erro uma vez e use um valor de string dessa forma e então você provavelmente deveria dizer adeus aos seus dados. Mau hábito!


"SELECT * FROM Product WHERE Id =" + TextBox1.Text


Embora não seja sua pergunta, mas talvez útil para leitores futuros:


Desastre de segurança !
Mesmo quando o Idcampo é inteiro, sua consulta pode estar sujeita à injeção de SQL. Suponha que você tenha uma consulta em seu aplicativo "SELECT * FROM Table1 WHERE Id=" + TextBox1.Text. Um invasor pode inserir na caixa de texto 1; DELETE Table1e a consulta será:

"SELECT * FROM Table1 WHERE Id=1; DELETE Table1"

Se você não quiser usar a consulta parametrizada aqui, você deve usar os valores digitados:

string.Format("SELECT * FROM Table1 WHERE Id={0}", int.Parse(TextBox1.Text))


Sua pergunta


Minha pergunta surgiu porque um colega de trabalho escreveu um monte de consultas concatenando valores inteiros, e eu estava me perguntando se seria uma perda de tempo revisar e corrigir todas elas.

Acho que mudar esses códigos não é perda de tempo. Na verdade, a mudança é recomendada!

se seu colega de trabalho usa variáveis ​​int, não há risco de segurança, mas acho que alterar esses códigos não é perda de tempo e, de fato, é recomendável alterar esses códigos. Torna o código mais legível, mais sustentável e torna a execução mais rápida.

Reza Aghaei
fonte
Mesmo a primeira opção não é totalmente adequada para a segurança. O comportamento do .ToString()é determinado por um item de configuração do sistema operacional que é fácil de alterar para incluir texto arbitrário.
Joel Coehoorn de
18

Na verdade, existem duas perguntas em uma. E a questão do título tem muito pouco a ver com as preocupações expressas pelo OP nos comentários posteriores.

Embora eu perceba que para o OP é o caso particular que importa, para os leitores vindos do Google, é importante responder à pergunta mais geral, que pode ser formulada como "a concatenação é tão segura quanto as declarações preparadas se eu tivesse certeza que cada literal que estou concatenando é seguro? ". Então, eu gostaria de me concentrar neste último. E a resposta é

Definitivamente não.

A explicação não é tão direta como a maioria dos leitores gostaria, mas vou tentar o meu melhor.

Estive refletindo sobre o assunto por um tempo, resultando no artigo (embora baseado no ambiente PHP) onde tentei resumir tudo. Ocorreu-me que a questão da proteção contra injeção de SQL costuma ser evitada em relação a alguns tópicos relacionados, mas mais restritos, como escape de string, conversão de tipo e outros. Embora algumas das medidas possam ser consideradas seguras quando tomadas por si mesmas, não existe um sistema, nem uma regra simples a seguir. O que torna o terreno muito escorregadio, colocando muito na atenção e experiência do desenvolvedor.

A questão da injeção de SQL não pode ser simplificada para uma questão de sintaxe específica. É mais amplo do que o desenvolvedor médio costumava pensar. É uma questão metodológica também. Não se trata apenas de "Qual formatação específica devemos aplicar", mas também de " Como isso deve ser feito".

(Deste ponto de vista, um artigo de Jon Skeet citado na outra resposta está indo bem mais mal do que bem, já que está novamente criticando algum caso extremo, concentrando-se em um problema de sintaxe específico e falhando em resolver o problema como um todo.)

Quando você está tentando abordar a questão da proteção não como um todo, mas como um conjunto de diferentes questões de sintaxe, você está enfrentando uma infinidade de problemas.

  • a lista de opções de formatação possíveis é realmente enorme. Significa que alguém pode facilmente ignorar alguns. Ou confunda-os (usando escape de string para identificador, por exemplo).
  • A concatenação significa que todas as medidas de proteção devem ser executadas pelo programador, não pelo programa. Este problema sozinho leva a várias consequências:
    • essa formatação é manual. Manual significa extremamente sujeito a erros. Pode-se simplesmente esquecer de se inscrever.
    • além disso, existe a tentação de mover os procedimentos de formatação para alguma função centralizada, bagunçando ainda mais as coisas e danificando os dados que não vão para o banco de dados.
  • quando mais de um desenvolvedor está envolvido, os problemas se multiplicam por um fator de dez.
  • quando a concatenação é usada, não é possível identificar uma consulta potencialmente perigosa: todas são potencialmente perigosas!

Ao contrário dessa bagunça, as declarações preparadas são de fato O Santo Graal:

  • pode ser expresso na forma de uma regra simples que é fácil de seguir.
  • é uma medida essencialmente indissociável, significa que o desenvolvedor não pode interferir e, voluntária ou involuntariamente, estragar o processo.
  • a proteção contra injeção é, na verdade, apenas um efeito colateral das instruções preparadas, cujo propósito real é produzir instruções sintaticamente corretas. E uma declaração sintaticamente correta é 100% à prova de injeção. Ainda assim, precisamos que nossa sintaxe esteja correta, apesar de qualquer possibilidade de injeção.
  • se usado em todas as direções, ele protege o aplicativo independentemente da experiência do desenvolvedor. Digamos, existe uma coisa chamada injeção de segunda ordem . E uma ilusão muito forte que diz "para proteger, escapar de todas as entradas fornecidas pelo usuário ". Combinados, eles levam à injeção, se um desenvolvedor toma a liberdade de decidir o que precisa ser protegido e o que não.

(Pensando mais, descobri que o conjunto atual de marcadores de posição não é suficiente para as necessidades da vida real e deve ser estendido, tanto para as estruturas de dados complexas, como matrizes, e até mesmo palavras-chave SQL ou identificadores, que às vezes precisam ser adicionados ao consulta dinamicamente também, mas um desenvolvedor é deixado desarmado para tal caso e forçado a voltar para a concatenação de string, mas isso é uma outra questão).

Curiosamente, a controvérsia desta questão é provocada pela natureza muito controversa de Stack Overflow. A ideia do site é fazer uso de perguntas específicas de usuários que perguntam diretamente para atingir o objetivo de ter um banco de dados de respostas de propósito geral adequado para usuários que vêm de pesquisa . A ideia não é ruim em si , mas falha em uma situação como esta: quando um usuário faz uma pergunta muito restrita , principalmente para obter uma discussão em uma disputa com um colega (ou para decidir se vale a pena refatorar o código). Enquanto a maioria dos participantes experientes tenta escrever uma resposta, tendo em mente a missão de Stack Overflow como um todo, tornando sua resposta adequada para o maior número possível de leitores, não apenas para o OP.

Seu senso comum
fonte
10
Não respondendo à pergunta
edc65
A maioria dos bancos de dados detecta consultas parametrizadas já usadas por igualdade de string SQL, então o antigo método prepare-and-use-handle parece desatualizado para mim. Esses identificadores podem ser usados ​​apenas dentro de um determinado escopo e requerem codificação para manter o controle do identificador. As consultas parametrizadas devem, em minha opinião, ser usadas diretamente, para que os planos de consulta possam ser reutilizados sem rastreamento de manipulação e até mesmo em diferentes aplicativos.
Erik Hart
15

Não vamos pensar apenas em considerações de segurança ou proteção de tipos.

O motivo pelo qual você usa consultas parametrizadas é para melhorar o desempenho no nível do banco de dados. De uma perspectiva de banco de dados, uma consulta parametrizada é uma consulta no buffer SQL (para usar a terminologia do Oracle, embora eu imagine que todos os bancos de dados tenham um conceito semelhante internamente). Assim, o banco de dados pode conter uma certa quantidade de consultas na memória, preparadas e prontas para execução. Essas consultas não precisam ser analisadas e serão mais rápidas. As consultas executadas com frequência geralmente estarão no buffer e não precisarão ser analisadas toda vez que forem usadas.

A MENOS QUE

Alguém não usa consultas parametrizadas. Neste caso, o buffer é continuamente liberado por um fluxo de consultas quase idênticas, cada uma das quais precisa ser analisada e executada pelo mecanismo de banco de dados e o desempenho é prejudicado, pois mesmo as consultas frequentemente executadas acabam sendo analisadas novamente muitas vezes por dia. Tenho sintonizado bancos de dados para viver e esta tem sido uma das maiores fontes de frutas ao alcance.

AGORA

Para responder à sua pergunta, SE sua consulta tiver um pequeno número de valores numéricos distintos, você provavelmente não estará causando problemas e pode, de fato, melhorar o desempenho infinitesimalmente. SE, entretanto, houver potencialmente centenas de valores e a consulta for muito chamada, você afetará o desempenho do seu sistema, portanto, não o faça.

Sim, você pode aumentar o buffer SQL, mas em última análise, é sempre às custas de outros usos mais críticos para a memória, como índices de cache ou dados. Moral, use consultas parametrizadas religiosamente para que você possa otimizar seu banco de dados e usar mais memória do servidor para as coisas que importam ...

mcottle
fonte
8

Para adicionar algumas informações à resposta de Maciek:

É fácil alterar as informações de cultura de um aplicativo de terceiros .NET chamando a função principal do assembly por reflexão:

using System;
using System.Globalization;
using System.Reflection;
using System.Threading;

namespace ConsoleApplication2
{
  class Program
  {
    static void Main(string[] args)
    {
      Assembly asm = Assembly.LoadFile(@"C:\BobbysApp.exe");
      MethodInfo mi = asm.GetType("Test").GetMethod("Main");
      mi.Invoke(null, null);
      Console.ReadLine();
    }

    static Program()
    {
      InstallBobbyTablesCulture();
    }

    static void InstallBobbyTablesCulture()
    {
      CultureInfo bobby = (CultureInfo)CultureInfo.InvariantCulture.Clone();
      bobby.DateTimeFormat.ShortDatePattern = @"yyyy-MM-dd'' OR ' '=''";
      bobby.DateTimeFormat.LongTimePattern = "";
      bobby.NumberFormat.NegativeSign = "1 OR 1=1 OR 1=";
      Thread.CurrentThread.CurrentCulture = bobby;
    }
  }
}

Isso só funciona se a função principal do BobbysApp for pública. Se Main não for público, pode haver outras funções públicas que você pode chamar.

user1027167
fonte
1
Você nem mesmo precisa fazer isso por código. Você pode adicionar injeção diretamente nas Configurações regionais do Windows. Veja minha resposta.
Kaspars Ozols
2
Quem pode alterar as configurações do servidor ou quem pode esfregar esse código no servidor? Se uma pessoa pode fazer isso no seu servidor, ela não precisa do SQL Injection para destruir os dados.
Reza Aghaei
7

Na minha opinião, se você pode garantir que o parâmetro com o qual está trabalhando nunca conterá uma string, é seguro, mas eu não faria isso em nenhum caso. Além disso, você verá uma ligeira queda no desempenho devido ao fato de estar executando a concatenação. A pergunta que eu faria é por que você não quer usar parâmetros?

Max
fonte
1
Não é que eu não queira usar parâmetros, estou usando parâmetros. Um colega de trabalho escreveu um código como este que modifiquei para ser parametrizado hoje, o que me fez pensar na questão.
johnnyRose de
Está bem. Ótimo. É uma prática recomendada usar parâmetros. Dessa forma, você não precisa se preocupar com coisas como injeção de sql. Além disso, se estiver criando consultas dinâmicas, você também pode usar parâmetros, não importando o quão complexas sejam suas consultas. Basta usar o estilo @ 1 ... @ n ao criá-los. E anexe-os à coleção de parâmetros com o valor desejado.
Máximo de
@johnyRose Há mais um ponto para usar parâmetros: os programas estão evoluindo e mudando. Você pode usar concatenação apenas para string, mas isso não garante que alguém implemente a refatoração que altere algum tipo de parâmetro e que as alterações possam introduzir a vulnerabilidade de injeção SQL.
lerthe61
3

Está tudo bem, mas nunca é seguro .. e a segurança sempre depende das entradas, por exemplo se o objeto de entrada for TextBox, os atacantes podem fazer algo complicado já que a caixa de texto pode aceitar string, então você tem que colocar algum tipo de validação / conversão para ser capaz de evitar a entrada errada dos usuários. Mas o fato é que não é seguro. Simples assim.

japzdivino
fonte
No entanto, isso é uma corda. Estou falando sobre outros tipos de dados, como inteiros, booleanos ou datetimes.
johnnyRose
@johnnyRose Sim, eu vi um exemplo muito bom acima que você marca como respondido por Kaspards .. e uma ótima resposta, pois ele usa o tipo de dados datetime como um exemplo, o que é incomum. :) Espero que você já esteja convencido de que não é seguro e melhor usar parâmetros em qualquer tipo de tipo de dados
japzdivino 05/10/2015
Nunca tive dúvidas de que era mais seguro usar parâmetros. Minha pergunta se refere a implementações fortemente tipadas.
johnnyRose
Sim .. eu concordo. e essa também é uma ótima pergunta que pode ajudar futuros leitores :)
japzdivino
-2

Não, você pode obter um ataque de injeção de SQL dessa forma. Escrevi um antigo artigo em turco que mostra como fazer aqui . Exemplo de artigo em PHP e MySQL, mas o conceito funciona da mesma forma em C # e SQL Server.

Basicamente, você ataca o seguinte caminho. Vamos considerar que você tem uma página que mostra informações de acordo com o valor do id inteiro. Você não parametrizou isso em valor, como abaixo.

http://localhost/sqlEnjeksiyon//instructors.aspx?id=24

Ok, suponho que você esteja usando o MySQL e eu ataco da seguinte maneira.

http://localhost/sqlEnjeksiyon//instructors.aspx?id=ASCII((SELECT%20DATABASE()))

Observe que aqui o valor injetado não é string. Estamos alterando o valor char para int usando a função ASCII. Você pode realizar a mesma coisa no SQL Server usando "CAST (YourVarcharCol AS INT)".

Depois disso, uso as funções de comprimento e substring para descobrir o nome do seu banco de dados.

http://localhost/sqlEnjeksiyon//instructors.aspx?id=LEN((SELECT%20DATABASE()))

http://localhost/sqlEnjeksiyon//instructors.aspx?id=ASCII(SUBSTR(SELECT%20DATABASE(),1,1))

Então, usando o nome do banco de dados, você começa a obter nomes de tabelas no banco de dados.

http://localhost/sqlEnjeksiyon//instructors.aspx?id=ASCII(SUBSTR((SELECT table_name FROM INFORMATION_SCHEMA.TABLES LIMIT 1),1,1))

Claro que você tem que automatizar este processo, uma vez que você obtém apenas UM caractere por consulta. Mas você pode automatizar isso facilmente. Meu artigo mostra um exemplo em watir . Usando apenas uma página e valor de ID não parametrizado. Posso aprender cada nome de tabela em seu banco de dados. Depois disso, posso procurar tabelas importantes. Isso vai levar algum tempo, mas é possível.

Atilla Ozgur
fonte
2
Minha pergunta se refere a uma linguagem fortemente tipada. Embora sua explicação seja ótima para idiomas com digitação flexível, o valor injetado ainda é uma string.
johnnyRose
Nenhum valor injetado é inteiro. Você obtém char e muda para inteiro usando a função ASCII MySQL. Você faz a mesma coisa no SQL Server usando CAST (YourCharValue AS INT)
Atilla Ozgur
Eu quis dizer algo assim:public void QuerySomething(int id) { // this will only accept an integer }
johnnyRose
-3

Bem ... uma coisa é certa: Segurança NÃO está ok, quando você concatenar uma string (tomada pelo usuário) com sua string de comando SQL. Não importa sempre que a cláusula where se refere a um inteiro ou a qualquer tipo; podem ocorrer injeções.

O que importa no SQL Injection é o tipo de dados da variável que costumava obter o valor do usuário.

Supondo que tenhamos um número inteiro na cláusula where e:

  1. a variável do usuário é uma string. Então ok, não é muito fácil de injetar (usando UNION), mas é muito fácil de contornar usando ataques do tipo 'OR 1 = 1' ...

  2. Se a variável do usuário for um inteiro. Então, novamente podemos 'testar' a força do sistema, passando no teste de grandes números incomuns para travamentos do sistema ou mesmo para um estouro de buffer oculto (na string final) ...;)

Talvez os parâmetros para consultas ou (melhor ainda - imo) para Procedimentos armazenados não sejam 100% seguros contra ameaças, mas são a medida menos necessária (ou elementar se você preferir) para minimizá-los.

Andreas Venieris
fonte
Acho que você pode ter entendido mal a pergunta. Estou falando sobre tipos não- string.
johnnyRose
Oi JonnyRose ... obrigado pela sua nota. Eu entendo sua pergunta, mas acabei de colocar minha resposta de uma forma mais geral. Para o caso de não string, verifique meu (2) ponto. ;)
Andreas Venieris