2015-10-15 22 views
7

Mam tabelę Project z dwiema kolumnami - ProjectId i ProjectName - i piszę funkcję, która tworzy i wykonuje SqlCommand, aby wysłać zapytanie do bazy danych o identyfikatorach projektu o podanej nazwie. Polecenie to działa, ale jest podatny na SQL Injection:Dlaczego String.Format działa, ale SqlCommand.Parameters.Add nie?

string sqlCommand = String.Format("SELECT {0} FROM {1} WHERE {2} = {3}", 
      attributeParam, tableParam, idParam, surroundWithSingleQuotes(idValue)); 

SqlCommand command = new SqlCommand(sqlCommand, sqlDbConnection); 
using (SqlDataAdapter adapter = new SqlDataAdapter(command)) 
{ 
    DataTable attributes = new DataTable(); 
    adapter.Fill(attributes); 
    ... 
} 

attributeParam, tableParam, idParam i idValue są wszystkie ciągi. Na przykład mogą być odpowiednio: "ProjectId", "Project", "ProjectName" i "MyFirstProject". surroundWithSingleQuotes otacza ciąg znaków z '', czyli surroundWithSingleQuotes(idValue) == "'MyFirstProject'". Próbuję napisać tę funkcję tak ogólną, jak to tylko możliwe, ponieważ mógłbym chcieć uzyskać cały dany atrybut z tabeli w przyszłości.

Chociaż powyższy String.Format działa, to nie:

string sqlCommand = String.Format("SELECT @attributeparam FROM {0} WHERE " + 
    "@idparam = @idvalue", tableParam); 

command.Parameters.Add(new SqlParameter("@attributeparam", attributeParam)); 
command.Parameters.Add(new SqlParameter("@idparam", idParam)); 
command.Parameters.Add(new SqlParameter("@idvalue", 
    surroundWithSingleQuotes(idValue))); 

SqlCommand command = new SqlCommand(sqlCommand, sqlDbConnection); 
using (SqlDataAdapter adapter = new SqlDataAdapter(command)) 
{ 
    DataTable attributes = new DataTable(); 
    adapter.Fill(attributes); 
    ... 
} 

nie jestem pewien dlaczego. Nie otrzymuję komunikatu o błędzie, ale kiedy napiszę DataTable używając SqlDataAdapter, DataTable nie zawiera nic. Oto różne podejścia wziąłem, bezskutecznie:

  • Po this answer i Microsoft's documentation, wykorzystujące AddWithValue lub wykorzystujące Parameters.Add i SqlParameter.Value.
  • Selektywne zastępowanie {0}, {1}, {2} i {3} w String.Format z rzeczywistą wartością lub ciągiem parametrów.

W innych miejscach w moim kodzie użyłem sparametryzowanych zapytań (choć z jednym parametrem) bez problemu.

+2

Jedynymi parametrami elementów, które można bezpośrednio zastąpić, jest '{3}'. –

+2

Nie można użyć parametru dla nazwy kolumny. Wciąż będziesz musiał użyć do tego 'string.Format', podobnie jak w przypadku nazwy tabeli. – juharr

Odpowiedz

7

Zasadniczo parametry w SQL działają tylko dla wartości - bez identyfikatorów kolumn lub tabel. W twoim przykładzie tylko ostatni parametr reprezentuje wartość.

Jeśli potrzebujesz dynamicznych pod względem nazw kolumn i tabel, musisz samodzielnie zbudować tę część SQL. Należy zachować ostrożność pod ze wszystkich normalnych przyczyn związanych z atakami typu SQL injection. Najlepiej pozwolić na znaną białą listę wartości tabeli i kolumny. Jeśli chcesz być bardziej ogólny, sugerowałbym wykonanie bardzo restrykcyjnego sprawdzania poprawności i quote the identifiers, aby uniknąć konfliktów ze słowami kluczowymi (lub całkowicie je zabronić).

Oczywiście nadal używaj parametrów SQL dla wartości.

+0

Niezwykle pomocna - dziękuję bardzo! – rln

0

Jest to ważne stwierdzenie: SELECT * FROM SomeTable WHERE [email protected]

niniejsza nie jest: SELECT * FROM @param

Oznacza to, że można użyć parametrów dla wartości a nie nazw tabel, widoków nazwisk, nazw kolumn itp

Powiązane problemy