Możesz to osiągnąć (jeśli rozumiem, co próbujesz zrobić) za pomocą dynamicznego SQL.
Sztuczka polega na tym, że musisz utworzyć ciąg zawierający instrukcję SQL. Dzieje się tak, ponieważ nazwa tabeli musi być określona w rzeczywistym tekście SQL podczas wykonywania instrukcji. Odniesienia do tabeli i odniesienia do kolumn nie mogą być dostarczone jako parametry, muszą one pojawić się w tekście SQL.
Możesz więc zastosować coś takiego:
SET @stmt = 'INSERT INTO @tmpTbl1 SELECT ' + @KeyValue
+ ' AS fld1 FROM tbl' + @KeyValue
EXEC (@stmt)
Najpierw tworzymy instrukcję SQL jako ciąg. Biorąc pod uwagę @KeyValue „Foo”, spowoduje to utworzenie ciągu zawierającego:
'INSERT INTO @tmpTbl1 SELECT Foo AS fld1 FROM tblFoo'
W tym momencie to tylko sznurek. Ale możemy wykonać zawartość ciągu, jako dynamiczną instrukcję SQL, używając EXECUTE
(lub EXEC
w skrócie).
Oldschoolowy sp_executesql
Procedura jest alternatywą dla EXEC, innego sposobu wykonywania dynamicznego SQL, który pozwala również na przekazywanie parametrów, zamiast określania wszystkich wartości jako literałów w tekście instrukcji.
KONTYNUACJA
EBarr wskazuje (poprawnie i co ważne), że takie podejście jest podatne na wstrzyknięcie SQL.
Zastanów się, co by się stało, gdyby @KeyValue
zawierał ciąg:
'1 AS foo; DROP TABLE students; -- '
Łańcuch, który stworzylibyśmy jako wyrażenie SQL, to:
'INSERT INTO @tmpTbl1 SELECT 1 AS foo; DROP TABLE students; -- AS fld1 ...'
Kiedy wykonujemy ten ciąg jako instrukcję SQL:
INSERT INTO @tmpTbl1 SELECT 1 AS foo;
DROP TABLE students;
-- AS fld1 FROM tbl1 AS foo; DROP ...
I to nie jest tylko DROP TABLE, który można wstrzyknąć. Można wstrzyknąć dowolny kod SQL, który może być znacznie subtelniejszy i jeszcze bardziej nikczemny. (Pierwszymi atakami mogą być próby odzyskania informacji o tabelach i kolumnach, a następnie próby pobrania danych (adresów e-mail, numerów kont itp.)
Jednym ze sposobów rozwiązania tej luki jest sprawdzenie poprawności zawartości @KeyValue, powiedzmy, że powinna ona zawierać tylko znaki alfabetyczne i numeryczne (np. sprawdź, czy nie ma znaków spoza tych zakresów, używając LIKE '%[^A-Za-z0-9]%'
. Jeśli zostanie znaleziony niedozwolony znak, odrzuć wartość i wyjdź bez wykonywania żadnego SQL.