2009-04-01 7 views
7

Aus Gründen der Argumentation, sagen wir einfach ich haben eine lokale Variable erstellen eine SQL-Abfrage enthält, die eine INSERT hat:SQL Server: Sanitizing @param gegen Injection-Angriffe

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

Diese INSERT ist auch geht auf einen Spaltenwert enthalten:

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

Nun, ich bin über eine Injektions Angriff offensichtlich besorgt, und möchte, dass @ Nachricht Wert, um sicherzustellen, kann nicht @ Einsatz Wert böswillige oder fehlerhaft als eine Abfrage machen exec .

Das bringt uns zu meiner Frage: Entkommt die Zeichen in @Message ausreichend? Gibt es noch andere Zeichen, die in @message erscheinen könnten, die auslaufen könnten?

Beispiel:

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

(Wenn ich sage „zu haben“, ist dies, weil meine Abfrage in einer gespeicherten Prozedur ist, und diese gespeicherte Prozedur akzeptiert @table, die die Zieltabelle einzufügen ist Ich bin nicht daran interessiert, meine Architektur zu diskutieren, oder warum die Tabelle, in die INSERT eingefügt werden soll, über einen Prozedurparameter "dynamisch" angegeben wird. Bitte beachten Sie , es sei denn, es gibt eine andere Möglichkeit als EXEC() eine Abfrage zur Angabe einer Tabelle INSERT, wenn dann der Tabellenname als Prozedurparameter empfangen wird.)

+1

Wollen wir uns wirklich mit Fragen beschäftigen, die sich mit absichtlich falschem Code beschäftigen? – dkretz

+7

Wenn es bedeutet, eine Lösung zu finden, ja. Entwickler müssen sich ständig mit Mist-Code auseinandersetzen, vor allem, wenn Sie Projekte in Bangladesch für $ 8 pro Stunde konsultieren und erben. Wir haben nicht immer den Luxus, Projekte von Grund auf neu zu entwickeln und sie so zu gestalten, wie sie sein sollten.:) – core

Antwort

10

Verwenden Sie sp_executesql und das integrierte quotename(). Dieser Artikel, The Curse and Blessings of Dynamic SQL, ist so ziemlich die definitive Referenz.

+0

++ kanonische Referenz – dkretz

+0

Offenbar gibt es eine quotename(), auch in 2008, ein Limit von 128 Länge, da es eine SQL-Kennung erwartet. Die Referenz schlägt vor, eine Funktion namens quotstring() zu erstellen (http://www.sommarskog.se/dynamic_sql.html#quotestring), die genau das Gleiche tut wie REPLACE (@variable, '' '', '' '' ''). – core

1

Anstatt EXEC (@somesql) aufzurufen, empfehle ich die Verwendung der sp_executesql stored procedure. Insbesondere können Sie Parameter übergeben, und das System überprüft, ob die Parameter gültig sind.

+0

Ja, leider sagt mir SQL Server 2008 Express "muss die Tabellenvariable '@my_table' deklarieren." nach der Ausführung dieses Codes. – core

+0

Ich war mir sicher, dass ich dies in SQL Server 2005 getan habe, aber ich gebe zu, dass ich einfach sehr, sehr müde sein könnte. Ich entschuldige mich. Ich werde das morgen versuchen. –

+0

Nein, ich liege falsch. Ich werde diesen Teil der Antwort entfernen. –

1

Sie könnten die Schemainformationen zuerst mit regulärem T-SQL abfragen und sicherstellen, dass der Tabellenname zuerst existiert. Auf diese Weise wird SQL, wenn es falsch formatiert ist, nicht als Code ausgeführt. Es wird nur ein VARCHAR Tabellenname sein.

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' 

(Oder verwenden Sie einfach IF EXISTS (SELECT ....))

+0

Gutes Denken. Ich habe getan, was folgt. Gibt es einen Vorteil von beiden? Was ich gemacht habe: "IF OBJECT_ID (@ Tabelle, 'U') ist NULL ..." – core

0

Offenbar gibt es eine 128-Längengrenze zu QUOTENAME(), auch im Jahr 2008 nach meinem Test, da es eine SQL erwartet Kennung. Die Referenz schlägt die Schaffung eine quotestring()-Funktion, die das gleiche tut wie:

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

Deshalb schlage ich, dass die Antwort ist eine Funktion aus der replace() oben zu schaffen, etwa so:

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

... Es sei denn, ich habe etwas falsch verstanden.

+0

Können Sie einen Nvarchar (MAX) als Parameter übergeben? –

+0

Sicher, warum nicht? Es ist jetzt eine Betriebsfunktion in meinem Entwickler. Umgebung. :) – core

Verwandte Themen