Czy nadal powinniśmy używać QUOTENAME do ochrony przed atakami iniekcyjnymi?

9

Patrzyłem dziś na starą procedurę składowaną i zauważyłem, że używała quotenameparametrów wejściowych. Po kilku kopaniach, aby dowiedzieć się, co to dokładnie zrobiłem, natknąłem się na tę stronę . Teraz rozumiem, co robi i jak go używać, ale strona twierdzi, że jest on używany jako środek łagodzący ataki SQL Injection. Kiedy tworzyłem aplikacje, które bezpośrednio przeszukiwały bazę danych, używając asp.net, korzystałem z parametrów ADO.Net, aby przekazywać dane wejściowe użytkownika jako dosłowną wartość i nigdy tak naprawdę nie martwiłem się o ich ochronę w moich procedurach przechowywanych.

Piszę teraz procedurę przechowywaną, która będzie używana przez aplikacje, których nie piszę, więc muszę próbować chronić się przed atakami wstrzykiwania na poziomie procedury, jest quotenameto najlepszy sposób, aby to zrobić, lub czy jest dostępna nowsza funkcja / lepsza metoda?

Kod, który doprowadził mnie do tego wzorca myślenia ( @parm1jest parametrem wejściowym użytkownika):

'SELECT project [Project], project_desc [Description], 
        customer [Customer], cpnyid [Company]
FROM PJPROJ (nolock)
where project like ' + quotename(@parm1,'''') + '
Matthew Verstraete
źródło

Odpowiedzi:

17

Tak, niewiele się zmieniło w tym obszarze, powinieneś używać quotenamewszystkich nazw obiektów serwera SQL używanych w dynamicznym SQL (zwłaszcza jeśli są one dostarczane zewnętrznie do twojego kodu). Oprócz ograniczania wstrzykiwania SQL oznacza to również, że kod będzie działał poprawnie w przypadku niestandardowych nazw identyfikatorów.

Ta funkcja jest odpowiednia tylko dla nazw obiektów (np. Nazwy tabel, kolumn, baz danych).

Powinieneś spróbować sparametryzować wszystko inne i użyć sp_executesql, przekazując parametry zamiast konkatenując je z ciągiem zapytania.

Ostatecznym artykułem na ten temat jest nadal Klątwa i błogosławieństwa dynamicznego SQL


Edytować. Teraz podałeś kod. Widzę, że przekazuje drugi parametr, 'aby dodać cudzysłowy zewnętrzne i uniknąć pojedynczych cudzysłowów, podwajając je przed wstrzyknięciem do łańcucha. To nie jest dobre użycie nazwy pliku. Nie powiedzie się (zwróci null), jeśli łańcuch ma więcej niż 128 znaków.

Dodatkowo może nadal pozostawić możliwość wstrzykiwania SQL, jeśli łańcuch zawiera U + 02BC zamiast standardowego apostrofu, a następnie łańcuch zostanie przypisany do varchar po sanitacji ( gdzie może po cichu zostać przekonwertowany na zwykły apostrof )

Prawidłowym sposobem na to jest sparametryzowanie zapytania. A następnie przekaż @parm1wartość dosys.sp_executesql

DECLARE @Sql NVARCHAR(MAX);

SET @Sql = '
SELECT project      [Project],
       project_desc [Description],
       customer     [Customer],
       cpnyid       [Company]
FROM   PJPROJ (nolock)
WHERE  project LIKE @parm1 
';

EXEC sys.sp_executesql
  @Sql,
  N'@parm1 varchar(100)',
  @parm1 = 'foobar%'; 
Martin Smith
źródło