2011-12-19 6 views
5

Questo può essere facilmente inserito qui perché il parametro @ID può essere praticamente qualsiasi cosa in questa istruzione SQL immettendolo, tuttavia, come si impedisce questo exploit?Creazione di una stored procedure di SQL Server sicura dalle iniezioni SQL

Preferisco impedire specificamente questo exploit a questo livello piuttosto che a livello di applicazione, qualche suggerimento?

CREATE PROCEDURE [dbo].[GetDataByID] 
@ID bigint, 
@Table varchar(150) 
AS 
BEGIN 

Declare @SQL Varchar(1000) 

SELECT @SQL = 'SELECT * FROM ' + @Table + ' WHERE ID = ' + CONVERT(varchar,@ID) 

SET NOCOUNT ON; 

EXEC(@sql) 
END 
+1

Solo una piccola cosa che non influisce molto sulle cose, ma non è il parametro '@ Table' che è il problema qui? '@ ID' è un' bigint', quindi può essere solo un numero quando si raggiunge il punto di costruzione dell'istruzione SQL dinamica, giusto? –

+0

Suppongo che entrambi .. –

risposta

9

Controllare this page, ha una guida meravigliosa per SQL dinamico, e le opzioni per eseguire in modo sicuro

Nel tuo caso dovrebbe essere simile a questo:

SELECT @SQL = N'SELECT * FROM ' + quotename(@Table) + N' WHERE ID = @xid' 
EXEC sp_executesql @SQL, N'@xid bigint', @ID 
+0

+1 Per il collegamento a Sommarskog. – Oded

+1

+1 è la prima volta che conosco effettivamente qualcuno la cui attività mi imbatto in StackOverflow;) – Tao

+0

lol! Ciao Tao! :) –

1

1) creare una nuova tabella che avrà un PK dell'identità e contiene i nomi delle tabelle delle stringhe
2) inserire tutte/solo le tabelle valide consentite nella procedura
3) utilizzare questo int identità PK come valore del parametro di input (TableID) per la stored procedure
4) nella procedura, basta cercare il valore di stringa (nome tabella) dal PK di identità specificato e si è sicuri di concatenare quella stringa cercata nella query . 5) la tua clausola WHERE va bene dal momento che si passa in un

int
0

Si consiglia di evitare del tutto sql dinamico. I problemi sono i seguenti:

  • L'iniezione ovvia allegare scenario
  • attacchi di iniezione binarie sono molto più intelligenti e possono bypassare stringa tradizionale fuga
  • prestazioni è quello grande - SQL Server è progettato per gestire i piani di esecuzione su stored procedure e verranno eseguite più velocemente rispetto alle query create dinamicamente. Se si sta utilizzando SQL dinamico, non vi è alcun vantaggio reale sull'utilizzo di una stored procedure. Se si desidera flessibilità nel codice per la selezione da più tabelle, è necessario prendere in considerazione un ORM o qualcosa per rendere più semplice il codice. Considerando che devi passare dinamicamente nella tabella, allora direi che non ha senso una procedura come quella sopra e una soluzione diversa è l'opzione migliore. Se si sta solo scrivendo contro SQL (cioè senza ORM), quindi il codice che genera processi separati sarebbe addirittura un'opzione migliore.

NOTA QUOTENAME NON GARANTIRà che si è sicuri dell'iniezione. L'iniezione di troncamento è ancora possibile. Leggi http://msdn.microsoft.com/en-us/library/ms161953.aspx prima di usarlo.

+0

Grazie per la risposta, ma puoi pubblicare un link di lavoro su QUOTENAME? –

+0

Non so cosa sia successo lì :) Dovrebbe funzionare ora. – Gats

0

Anche se mi piacerebbe dare consigli su SQL dinamico in generale, in questo caso penso che si possa farla franca controllando se la variabile @Table contiene un nome di tabella valido.

  • La domanda è se si ha intenzione di permettere nomi di schema e/o query cross-db, io' a patto che non vuole andare fuori del db (o server) qui, ma non consentono di diverso schema di (AdventureWorks mostra come possono essere utilizzati)
  • POTREBBE anche includere le visualizzazioni per @Table.
  • Probabilmente sarebbe "bello" se si controllasse anche se l'oggetto trovato avesse effettivamente una colonna ID e generato un errore "userfriendly" in caso contrario. Opzionale però.

Basta inserire QuoteName() intorno a @table NON ti proteggerà da tutto.Nonostante una grande funzione, è tutt'altro che perfetta. IMHO la soluzione migliore sarebbe analizzare la variabile @Table, controllare se il suo contenuto è valido e quindi creare SQL dinamico in base alle parti ottenute. Ho iniziato a fare la maggior parte di sopra e sorprendentemente non richiede un sacco di verifica di qualcosa che sembra semplice come questo =)

CREATE PROCEDURE [dbo].[GetDataByID] ( 
             @ID bigint, 
             @Table nvarchar(300) 
            ) 
AS 

DECLARE @sql nvarchar(max) 

DECLARE @server_name sysname, 
     @db_name  sysname, 
     @schema_name sysname, 
     @object_name sysname, 
     @schema_id int   

SELECT @server_name = ParseName(@Table, 4), 
     @db_name  = ParseName(@Table, 3), 
     @schema_name = ParseName(@Table, 2), 
     @object_name = ParseName(@Table, 1) 

IF ISNULL(@server_name, @@SERVERNAME) <> @@SERVERNAME 
    BEGIN 
     RaisError('Queries are restricted to this server only.', 16, 1) 
     Return(-1) 
    END 

IF ISNULL(@db_name, DB_Name()) <> DB_Name() 
    BEGIN 
     RaisError('Queries are restricted to this database only.', 16, 1) 
     Return(-1) 
    END 


IF @schema_name IS NULL 
    BEGIN 
     IF NOT EXISTS (SELECT * 
          FROM sys.objects 
         WHERE name = @object_name 
          AND type IN ('U', 'V')) 
      BEGIN 
       RaisError('Requested @Table not found. [%s]', 16, 1, @object_name) 
       Return(-1) 
      END 

     SELECT @sql = 'SELECT * FROM ' + QuoteName(@object_name) + ' WHERE ID = @ID' 
    END 
ELSE 
    BEGIN 

     SELECT @schema_id = Schema_id(@schema_name) 

     IF @schema_id IS NULL 
      BEGIN 
       RaisError('Unrecognized schema requested [%s].', 16, 1, @schema_name) 
       Return(-1) 
      END 

     IF NOT EXISTS (SELECT * 
          FROM sys.objects 
         WHERE name = @object_name 
          AND schema_id = @schema_id 
          AND type IN ('U', 'V')) 
      BEGIN 
       RaisError('Requested @Table not found. [%s].[%s]', 16, 1, @schema_name, @object_name) 
       Return(-1) 
      END 

     SELECT @sql = 'SELECT * FROM ' + QuoteName(@schema_name) + '.' + QuoteName(@object_name) + ' WHERE ID = @ID' 
    END 

EXEC sp_executesql @stmt = @sql, 
        @params = N'@ID bigint', 
        @ID  = @ID 

Return(0)  

Supra compila, ma potrebbe essere necessario appianare alcuni bug come io didn' t abbastanza per quanto riguarda il controllo di tutti i percorsi di codice.

Problemi correlati