2009-04-01 3 views
7

Per amor di discussione, diciamo solo che ho devo creare una variabile locale contenente una query SQL che ha un inserto:SQL Server: Sanificazione @param contro gli attacchi di iniezione

DECLARE @insert NVARCHAR(MAX) 
SELECT @insert = 'INSERT INTO [dbo].[' + @table + '] VALUES... 
EXEC (@insert) 

Questo inserto è anche andando a contenere un valore di colonna:

DECLARE @insert NVARCHAR(MAX) 
SELECT @insert = 
    'INSERT INTO [dbo].[' + @table + '] VALUES (N''' + @message + ''')' 
EXEC (@insert) 

Ora, sono ovviamente preoccupato per un attacco di iniezione, e vorrei assicurare un valore di quel messaggio @ non è possibile effettuare il valore di @ inserto dannoso o malformati come una query a exec .

Questo ci porta alla mia domanda: è sufficiente l'escape dei caratteri in @message? Ci sono altri personaggi che potrebbero apparire in @message che potrebbero sfuggire?

Esempio:

DECLARE @insert NVARCHAR(MAX) 
SELECT @message = REPLACE(@message,'''','''''') 
SELECT @insert = 
    'INSERT INTO [dbo].[' + @table + '] VALUES (N''' + @message + ''')' 
EXEC (@insert) 

(quando dico "devono", questo è perché la mia domanda è in una stored procedure, e questa stored procedure accetta @Table, che è la tabella di destinazione di INSERT in. Non sono interessato a discutere la mia architettura o perché la tabella in INSERT è specificata "dinamicamente" tramite un parametro di procedura. Evita di commentare questo a meno che non ci sia un altro modo oltre a EXEC() in una query per specificare una tabella per INSERIRE quando il nome della tabella viene ricevuto come parametro di procedura.)

+1

Vogliamo davvero occuparci di domande che riguardano come scrivere intenzionalmente codice errato? – dkretz

+7

Se significa trovare una soluzione, sì. Gli sviluppatori devono sempre occuparsi del codice crap, specialmente se si consultano e si ereditano progetti scritti in Bangladesh per $ 8/ora. Non sempre otteniamo il lusso di costruire progetti da zero, costruendoli come dovrebbero * essere * stati.:) – core

risposta

10

Utilizzare sp_executesql e quotename() integrato. Questo articolo, The Curse and Blessings of Dynamic SQL, è praticamente il riferimento definitivo.

+0

++ riferimento canonico – dkretz

+0

Apparentemente c'è un limite di 128 lunghezza a quotename(), anche nel 2008, poiché si aspetta un identificatore SQL. Il riferimento suggerisce di creare una funzione quotestring() (http://www.sommarskog.se/dynamic_sql.html#quotestring), che fa esattamente la stessa cosa di REPLACE (@variable, '' '', '' '' ''). – core

1

Piuttosto che chiamare EXEC (@somesql), suggerisco di utilizzare lo sp_executesql stored procedure. In particolare, questo consente di passare i parametri e il sistema verificherà che i parametri siano validi.

+0

Sì, sfortunatamente, SQL Server 2008 Express mi dice "Devi dichiarare la variabile di tabella '@my_table'." dopo aver eseguito quel codice. – core

+0

Ero sicuro di averlo fatto in SQL Server 2005, ma ammetto che potrei essere davvero molto stanco. Chiedo scusa. Ci proverò domani. –

+0

No, ho sbagliato. Rimuoverò quella sezione della risposta. –

1

È possibile prima eseguire una query delle informazioni sullo schema con il normale T-SQL e assicurarsi che il nome della tabella esista prima. In questo modo, se è SQL malformato, non verrà eseguito come codice. Sarà solo un nome di tabella VARCHAR.

DECLARE @Table AS VARCHAR(MAX) 
DECLARE @Exists AS BIT 

SET @Table = 'Vicious malformed dynamic SQL' 

SELECT @Exists = COUNT(TABLE_NAME) 
FROM INFORMATION_SCHEMA.TABLES 
WHERE TABLE_NAME = @Table 

IF (@Exists = 1) 
    BEGIN 
    PRINT 'Table exists' 
    -- Execute dynamic SQL. 
    END 
ELSE 
    PRINT 'Invalid table' 

(O semplicemente utilizzare IF EXISTS (SELECT ....))

+0

Buon pensiero. Ho fatto ciò che segue. C'è qualche vantaggio o? Cosa ho fatto: "IF OBJECT_ID (@ table, 'U') È NULL ..." – core

0

A quanto pare c'è un limite a 128 di lunghezza per QUOTENAME(), anche nel 2008, secondo la mia prova, dal momento che si aspetta uno SQL identificatore. Il riferimento suggerisce di creare una funzione quotestring(), che fa la stessa cosa come:

REPLACE(@variable,'''','''''') 

Pertanto propongo che la risposta è di creare una funzione di REPLACE() di cui sopra, in questo modo:

CREATE FUNCTION quotestring(@string nvarchar(MAX)) 
RETURNS nvarchar(MAX) AS 
BEGIN 
    RETURN(REPLACE(@string,'''','''''')) 
END 

... A meno che non abbia frainteso qualcosa.

+0

Puoi passare un nvarchar (MAX) come parametro come quello? –

+0

Certo, perché no? Ora è una funzione operativa nel mio dev. ambiente. :) – core