Czy nie należy sparametryzować zapytania SQL, gdy parametr nie jest łańcuchem?

113

Jeśli chodzi o wstrzykiwanie SQL , w pełni rozumiem konieczność parametryzacji stringparametru; to jedna z najstarszych sztuczek w tej książce. Ale kiedy można uzasadnić brak parametryzacji SqlCommand? Czy jakiekolwiek typy danych są uważane za „bezpieczne”, jeśli nie można ich parametryzować?

Na przykład: nie uważam się nigdzie w pobliżu eksperta w SQL, ale nie mogę myśleć o jakichkolwiek przypadkach, gdzie byłoby potencjalnie narażone na SQL injection zaakceptować boolalbo inti po prostu złączyć je w prawo w zapytaniu.

Czy moje założenie jest prawidłowe, czy może to potencjalnie pozostawi dużą lukę w zabezpieczeniach mojego programu?

Dla wyjaśnienia, to pytanie zostało oznaczone tagiem który jest językiem silnie typizowanym; kiedy mówię „parametr”, pomyśl o czymś takim public int Query(int id) .

johnnyRose
źródło
14
Nie uzyskasz korzyści z planów zapytań w pamięci podręcznej, jeśli nie używasz parametrów, konieczne byłoby utworzenie osobnego planu zapytań dla każdej nowej kombinacji danych wejściowych, które podasz.
Scott Chamberlain
5
@MatthewWhited Skąd wiesz, że zajmuje to mniej czasu? Taka sytuacja występuje wszędzie w niektórych projektach od obecnego i poprzedniego dewelopera. Jeśli rzeczywiście poprawi to bezpieczeństwo, napisz odpowiedź. Dla jasności zgadzam się, że oczywiście lepiej jest sparametryzować. Ale to naprawdę nie jest moje pytanie.
johnnyRose
7
Zapytania sparametryzowane są używane głównie do wydajności i optymalizacji. Efektem ubocznym jest zapobieganie iniekcjom SQL.
Salman A,
13
Myślę, że OP zadał ważne pytanie. Próbuje oszacować koszty / korzyści naprawy potencjalnego ryzyka. to równanie zmienia się wraz z potencjałem tego ryzyka. jeśli nie ma ryzyka, też bym tego nie zrobił. Poproszono go o techniczne pytanie dotyczące potencjału, a nie o subiektywną ocenę tego, czy uważasz, że jest to warte jego czasu. OP jest jedyną osobą, która może wykonać to połączenie.
Sir Swears-a-lot
10
Aby się wytłumaczyć: jestem dba. Doceniam i szanuję najlepsze praktyki, aw idealnym świecie cały kod byłby doskonały. Niestety w świecie, w którym pracuję, mam więcej problemów do rozwiązania niż czasu na ich rozwiązanie. To oznacza ustalanie priorytetów. Przepisywanie kodu IMO, który już działa, jest bezpieczny i działa na akceptowalnym poziomie, brzmi jak luksus. (Na to mnie nie stać)
Sir Swears-a-lot

Odpowiedzi:

101

Myślę, że to bezpieczne ... technicznie , ale to straszny nawyk. Czy na pewno chcesz pisać takie zapytania?

var sqlCommand = new SqlCommand("SELECT * FROM People WHERE IsAlive = " + isAlive + 
" AND FirstName = @firstName");

sqlCommand.Parameters.AddWithValue("firstName", "Rob");

Naraża Cię również na sytuację, w której typ zmienia się z liczby całkowitej na ciąg znaków (Pomyśl o numerze pracownika, który pomimo swojej nazwy - może zawierać litery).

Więc zmieniliśmy typ EmployeeNumber z intna string, ale zapomnieliśmy zaktualizować nasze zapytania sql. Ups.

Rob
źródło
24
Czy możemy AddWithValue już przestać używać ? blogs.msmvps.com/jcoehoorn/blog/2014/05/12/…
RemarkLima
5
@RemarkLima Jakie jest rozwiązanie, gdy dynamicznie generujesz kod, który odwzorowuje wartości na parametry? Post na blogu nie odnosi się do tego scenariusza. Tak, to jeden wiersz do ustawienia typu SQL, gdy jest znany , ale jeśli nie jest, masz problem (lub musisz uciec się do adnotacji modeli z tymi informacjami).
casperOne,
1
Wtedy utkniesz z, AddWithValuechyba że masz mapowanie typów baz danych w ramach dynamicznego budowania instrukcji. Zakładam, że masz listę kolumn docelowych, a jako część słownika możesz mieć typy, jeśli chcesz. W przeciwnym razie po prostu przyjmij uderzenie wydajności. Ostatecznie myślę, że to po prostu dobra informacja.
Uwaga Lima
8
@RemarkLima Chodzi o to, że „Czy możemy AddWithValuejuż przestać używać ?” powinno naprawdę brzmieć „jeśli znasz typ, powinieneś powstrzymać się od używania AddWithValue.
casperOne
2
Hej, nie strzelaj do posłańca, nie napisałem tego ;-), ale kwestia pozostaje, a jeśli jest wbudowana w twoje projekty od samego początku, nie ma powodu, aby nie znać typu. Najlepsza praktyka i cały ten jazz :-)
RemarkLima
65

Podczas korzystania z silnie wpisany platformę na komputerze można sterować (jak serwer WWW), można zapobiec iniekcji kodu dla zapytań tylko bool, DateTimeczy int(i innych numerycznych) wartości. Niepokojące są problemy z wydajnością spowodowane zmuszeniem serwera sql do ponownej kompilacji każdego zapytania i uniemożliwianiem mu uzyskiwania dobrych statystyk dotyczących zapytań wykonywanych z jaką częstotliwością (co szkodzi zarządzaniu pamięcią podręczną).

Ale ta część „na komputerze, którym sterujesz” jest ważna, ponieważ w przeciwnym razie użytkownik może zmienić zachowanie używane przez system do generowania ciągów z tych wartości, aby uwzględnić dowolny tekst.

Lubię też myśleć długoterminowo. Co się stanie, gdy dzisiejsza stara i zniszczona silnie typowana baza kodu zostanie przeniesiona przez automatyczne tłumaczenie na dynamiczny język New-Hotness i nagle stracisz sprawdzanie typów, ale nie masz jeszcze wszystkich odpowiednich testów jednostkowych dla kodu dynamicznego ?

Naprawdę nie ma dobrego powodu, aby nie używać parametrów zapytania dla tych wartości. To właściwy sposób . Śmiało i zakoduj na stałe wartości w ciągu sql, gdy naprawdę są one stałymi, ale w przeciwnym razie dlaczego nie użyć po prostu parametru? To nie jest trudne.

Ostatecznie nie nazwałbym tego samym błędem , ale nazwałbym to zapachem : coś, co samo w sobie nie jest błędem, ale jest silną wskazówką, że błędy są w pobliżu lub w końcu będą. Dobry kod pozwala uniknąć pozostawiania zapachów, a każde dobre narzędzie do analizy statycznej to oznaczy.

Dodam, że nie jest to niestety rodzaj sporu, który można wygrać od razu. Wygląda na to, że sytuacja, w której „racja” już nie wystarcza, a nadepnięcie współpracownikom na palce, aby samodzielnie rozwiązać ten problem, nie sprzyja dobrej dynamice zespołu; ostatecznie może bardziej boleć niż pomaga. Lepszym podejściem w tym przypadku może być promowanie użycia narzędzia do analizy statycznej. To dałoby legitymację i wiarygodność wysiłkom zmierzającym do powrotu i naprawienia istniejącego kodu.

Joel Coehoorn
źródło
1
Zdecydowanie nie jest wyzwaniem zrobienie tego sparametryzowanego. Moje pytanie powstało, ponieważ współpracownik napisał kilka zapytań łączących wartości całkowite i zastanawiałem się, czy to strata czasu, aby je wszystkie rozwiązać.
johnnyRose
2
Myślę, że pytanie „Czy to błąd” jest tym, do czego sprowadza się moje pytanie.
johnnyRose
7
To „zapach”: coś, co samo w sobie nie jest błędem, ale wskazuje, że błędy są prawdopodobnie w pobliżu. Dobry kod stara się wyeliminować zapachy. Każde dobre narzędzie do analizy statycznej na pewno by to oznaczyło.
Joel Coehoorn
1
Podoba mi się określenie „zapach”. Zamiast tego użyłbym czegoś takiego jak „larwa”, gdzie to jeszcze nie jest błąd, ale przyszłe aktualizacje mogą go złapać na robaka, który będzie jadł na twoim zapleczu, dopóki go nie zmiażdżysz lub nie fumigujesz. Z pewnością nie chcesz, aby potencjał nekrotycznego kodu pojawił się w środowisku produkcyjnym, a posiadanie czegoś, co nie zostało opracowane z pewną finezją, z pewnością może spowodować, że taki będzie obecny, jak w tym przypadku.
CSS
1
To jest po prostu złe. Zobacz moją odpowiedź na przykład o tym, jak nadal możesz tworzyć wstrzyknięcia SQL za pomocą DateTimeorint
Kaspars Ozols
53

W niektórych przypadkach jest możliwe wykonanie ataku SQL injection z niesparametryzowanymi (konkatenowanymi) zmiennymi innymi niż wartości łańcuchowe - zobacz artykuł Jon: http://codeblog.jonskeet.uk/2014/08/08/the-bobbytables -kultura / .

Chodzi o to, że gdy ToStringjest wywoływana, jakiś niestandardowy dostawca kultury może przekształcić parametr niebędący ciągiem znaków w jego reprezentację w postaci ciągu, który wstrzykuje trochę kodu SQL do zapytania.

Maciek
źródło
14
Myślę, że to jedyny post, który odpowiada na pytanie, które zasadniczo brzmi: „Jak w ogóle możliwy jest zastrzyk z ints?”
Arturo Torres Sánchez
3
Chociaż jeśli jesteś w stanie wstrzyknąć niestandardowy kod, taki jak pułapki, CultureInfotrudno wiedzieć, dlaczego i tak potrzebujesz iniekcji SQL.
Martin Smith
plus 1, jedyna odpowiedź, która faktycznie odpowiada na pytanie
ken2k
@MartinSmith: zobacz moją odpowiedź, która pokazuje jeden możliwy sposób zmiany CultureInfo z zewnątrz.
user1027167
Jeśli ktoś potrafi napisać taki kod w aplikacji, to po co mu SQL Injection?
Reza Aghaei
51

Nie jest to bezpieczne nawet w przypadku typów niebędących ciągami. Zawsze używaj parametrów. Kropka.

Rozważ następujący przykład kodu:

var utcNow = DateTime.UtcNow;
var sqlCommand = new SqlCommand("SELECT * FROM People WHERE created_on <= '" + utcNow + "'");

Na pierwszy rzut oka kod wygląda na bezpieczny, ale wszystko się zmienia, jeśli wprowadzisz zmiany w ustawieniach regionalnych systemu Windows i dodasz wtrysk w formacie daty krótkiej:

Wstrzyknięcie daty i godziny

Teraz wynikowy tekst polecenia wygląda następująco:

SELECT * FROM People WHERE created_on <= '26.09.2015' OR '1'<>' 21:21:43'

To samo można zrobić dla inttypu, ponieważ użytkownik może zdefiniować niestandardowy znak ujemny, który można łatwo zmienić na iniekcję SQL.

Można argumentować, że zamiast bieżącej kultury należy używać niezmiennej kultury, ale widziałem takie konkatenacje ciągów wiele razy i łatwo jest przeoczyć, łącząc ciągi z obiektami przy użyciu +.

Kaspars Ozols
źródło
10
Kto może zmieniać ustawienia serwera? Jeśli ktoś może to zrobić na twoim serwerze, nie potrzebuje SQL Injection, aby zniszczyć dane.
Reza Aghaei
5
To najlepsza odpowiedź, pokazuje jeden sposób, który potwierdza obawy PO, to jest błąd / luka w zabezpieczeniach. Pomijając łączenie czasów danych w SQL, na przykład nie chodzi tylko o zapach lub dług technologiczny . @RezaAghaei pytanie nigdy nie dotyczyło strony serwera, może to być aplikacja Windows z SQLExpress - tak czy inaczej nie jest to kryterium pytania. Każdy może powiedzieć, ale kto ma dostęp do ustawień serwera, aby obalić tę doskonałą odpowiedź, tak jak każdy może powiedzieć, co o hostingu na serwerze współdzielonym lub błędzie Y2K. Zgadzam się z Tobą, że serwer jest zablokowany - to po prostu nie jest wymagane.
Jeremy Thompson,
2
Czy możesz podać przykład tego, co mówiłeś o tym inttypie?
johnnyRose
1
Wiem, że minęło kilka tygodni, odkąd na to odpowiedziałeś, ale czy możesz edytować swój post i dodać przykład, w jaki sposób możesz zdefiniować niestandardowy znak minus?
johnnyRose
23

"SELECT * FROM Table1 WHERE Id =" + intVariable.ToString ()


Bezpieczeństwo
Jest OK.
Atakujący nie mogą wstrzyknąć niczego do wpisanej zmiennej int.

Wydajność
Not OK.

Lepiej jest używać parametrów, więc zapytanie zostanie skompilowane raz i zapisane w pamięci podręcznej do następnego użycia. Następnym razem, nawet z różnymi wartościami parametrów, zapytanie jest buforowane i nie musi być kompilowane na serwerze bazy danych.

Styl kodowania
Zła praktyka.

  • Parametry są bardziej czytelne
  • Może to sprawia, że ​​przyzwyczaisz się do zapytań bez parametrów, a może kiedyś popełniłeś błąd i użyłeś w ten sposób wartości ciągu, a potem prawdopodobnie powinieneś pożegnać się ze swoimi danymi. Zły nawyk!


„SELECT * FROM Product WHERE Id =” + TextBox1.Text


Chociaż to nie jest twoje pytanie, ale może przydatne dla przyszłych czytelników:


Katastrofa bezpieczeństwa !
Nawet jeśli Idpole jest liczbą całkowitą, zapytanie może podlegać iniekcji SQL. Załóżmy, że masz zapytanie w swojej aplikacji "SELECT * FROM Table1 WHERE Id=" + TextBox1.Text, osoba atakująca może wstawić do pola tekstowego, 1; DELETE Table1a zapytanie będzie:

"SELECT * FROM Table1 WHERE Id=1; DELETE Table1"

Jeśli nie chcesz tutaj używać sparametryzowanego zapytania, powinieneś użyć wpisanych wartości:

string.Format("SELECT * FROM Table1 WHERE Id={0}", int.Parse(TextBox1.Text))


Twoje pytanie


Moje pytanie powstało, ponieważ współpracownik napisał kilka zapytań łączących wartości całkowite i zastanawiałem się, czy to strata czasu, aby je wszystkie rozwiązać.

Myślę, że zmiana tych kodów nie jest stratą czasu. Rzeczywiście zmiana jest zalecana!

jeśli twój współpracownik używa zmiennych int, nie ma to żadnego zagrożenia dla bezpieczeństwa, ale myślę, że zmiana tych kodów nie jest stratą czasu i rzeczywiście zaleca się zmianę tych kodów. Sprawia, że ​​kod jest bardziej czytelny, łatwiejszy w utrzymaniu i przyspiesza wykonywanie.

Reza Aghaei
źródło
Nawet pierwsza opcja nie jest całkowicie odpowiednia ze względów bezpieczeństwa. Zachowanie .ToString()jest określane przez element konfiguracji systemu operacyjnego, który można łatwo zmienić w celu uwzględnienia dowolnego tekstu.
Joel Coehoorn
18

W rzeczywistości są dwa pytania w jednym. A pytanie z tytułu ma niewiele wspólnego z obawami wyrażonymi przez PO w późniejszych komentarzach.

Chociaż zdaję sobie sprawę, że dla PO liczy się ich konkretny przypadek, dla czytelników pochodzących z Google ważne jest, aby odpowiedzieć na bardziej ogólne pytanie, które można sformułować jako „czy konkatenacja jest tak samo bezpieczna jak przygotowane oświadczenia, jeśli upewnię się że każdy literał, który konkatenuję, jest bezpieczny? ”. Chciałbym więc skoncentrować się na tym ostatnim. A odpowiedź brzmi

Zdecydowanie nie.

Wyjaśnienie nie jest tak bezpośrednie, jak chciałaby większość czytelników, ale postaram się jak najlepiej.

Od dłuższego czasu zastanawiałem się nad tą sprawą, czego efektem był artykuł (choć oparty na środowisku PHP), w którym próbowałem wszystko podsumować. Przyszło mi do głowy, że kwestia ochrony przed wstrzyknięciem SQL często wymyka się niektórym pokrewnym, ale węższym tematom, takim jak ucieczka ciągów, rzutowanie typów i tym podobne. Chociaż niektóre środki można uznać za bezpieczne, gdy są podejmowane samodzielnie, nie ma systemu ani prostej zasady do przestrzegania. To sprawia, że ​​jest to bardzo śliski grunt, zbytnio obciążający uwagę i doświadczenie programisty.

Kwestii iniekcji SQL nie można uprościć do kwestii konkretnego problemu składniowego. Jest szerszy niż zwykły myśleć programista. To także kwestia metodologiczna . Nie chodzi tylko o „Jakie konkretne formatowanie musimy zastosować”, ale także „ Jak to zrobić”.

(Z tego punktu widzenia artykuł Jona Skeeta cytowany w drugiej odpowiedzi radzi sobie raczej źle niż dobrze, ponieważ ponownie szuka dziury w jakimś skrajnym przypadku, koncentrując się na konkretnym problemie składniowym i nie rozwiązując problemu w całości).

Kiedy próbujesz rozwiązać kwestię ochrony nie jako całości, ale jako zestaw różnych problemów składniowych, napotykasz wiele problemów.

  • lista możliwych opcji formatowania jest naprawdę ogromna. Oznacza to, że można łatwo przeoczyć niektóre. Lub zmylić je ( na przykład używając znaków ucieczki dla identyfikatora ).
  • Konkatenacja oznacza, że ​​wszystkie środki ochrony muszą być wykonywane przez programistę, a nie program. Sam ten problem prowadzi do kilku konsekwencji:
    • takie formatowanie jest ręczne. Ręczny oznacza wyjątkowo podatny na błędy. Można po prostu zapomnieć o złożeniu wniosku.
    • ponadto istnieje pokusa, aby przenieść procedury formatowania do jakiejś scentralizowanej funkcji, co jeszcze bardziej komplikuje sprawę i psuje dane, które nie trafią do bazy danych.
  • gdy zaangażowanych jest więcej niż jeden programista, problemy mnożą się dziesięciokrotnie.
  • kiedy używana jest konkatenacja, nie można od razu określić potencjalnie niebezpiecznego zapytania: wszystkie są potencjalnie niebezpieczne!

W przeciwieństwie do tego bałaganu, przygotowane wypowiedzi są rzeczywiście Świętym Graalem:

  • można to wyrazić w postaci jednej prostej reguły, której łatwo przestrzegać.
  • jest to środek zasadniczo nieodczuwalny, co oznacza, że ​​deweloper nie może ingerować i, dobrowolnie lub niechętnie, zepsuć procesu.
  • ochrona przed iniekcją jest tak naprawdę tylko efektem ubocznym przygotowanych instrukcji, których realnym celem jest wytworzenie zdania poprawnego składniowo. A poprawne składniowo stwierdzenie jest w 100% odporne na iniekcje. Jednak potrzebujemy, aby nasza składnia była poprawna pomimo możliwości wstrzyknięcia.
  • jeśli jest używany dookoła, chroni aplikację niezależnie od doświadczenia programisty. Powiedzmy, jest coś, co nazywa się wtryskiem drugiego rzędu . I bardzo silne złudzenie, które brzmi „w celu ochrony, unikaj wszelkich danych wprowadzanych przez użytkownika ”. Połączone razem prowadzą do zastrzyku, jeśli deweloper ma swobodę decydowania, co należy chronić, a co nie.

(Myśląc dalej, odkryłem, że obecny zestaw symboli zastępczych nie wystarcza do zaspokojenia rzeczywistych potrzeb i musi zostać rozszerzony, zarówno w przypadku złożonych struktur danych, takich jak tablice, jak i nawet słów kluczowych lub identyfikatorów SQL, które czasami trzeba dodawać do zapytania również dynamicznie, ale programista jest nieuzbrojony w takim przypadku i zmuszony do powrotu do konkatenacji ciągów, ale to kwestia innego pytania).

Co ciekawe, kontrowersje związane z tym pytaniem wywołuje bardzo kontrowersyjny charakter Stack Overflow. Ideą serwisu jest wykorzystanie konkretnych pytań od użytkowników, którzy pytają bezpośrednio, aby osiągnąć cel, jakim jest posiadanie bazy odpowiedzi ogólnego przeznaczenia, odpowiedniej dla użytkowników pochodzących z wyszukiwania . Pomysł nie jest zły sam w sobie , ale zawodzi w takiej sytuacji: gdy użytkownik zadaje bardzo wąskie pytanie , szczególnie po to, aby uzyskać argument w sporze z kolegą (lub zdecydować, czy warto refaktoryzować kod). Podczas gdy większość doświadczonych uczestników próbuje napisać odpowiedź, mając na uwadze misję całego Stack Overflow, dzięki czemu ich odpowiedź jest dobra dla jak największej liczby czytelników, a nie tylko dla PO.

Twój zdrowy rozsądek
źródło
10
Brak odpowiedzi na pytanie
edc65
Większość baz danych wykrywa już używane, sparametryzowane zapytania na podstawie równości ciągów SQL, więc stara metoda obsługi przygotowania i użycia wydaje mi się przestarzała. Te uchwyty mogą być używane tylko w określonym zakresie i wymagają kodowania, aby śledzić uchwyt. Moim zdaniem sparametryzowane zapytania powinny być używane bezpośrednio, aby plany zapytań mogły być ponownie używane bez śledzenia uchwytów, a nawet w różnych aplikacjach.
Erik Hart
15

Nie myślmy tylko o kwestiach bezpieczeństwa lub bezpieczeństwa typów.

Powodem używania sparametryzowanych zapytań jest poprawa wydajności na poziomie bazy danych. Z punktu widzenia bazy danych sparametryzowane zapytanie to jedno zapytanie w buforze SQL (używając terminologii Oracle, chociaż wyobrażam sobie, że wszystkie bazy danych mają wewnętrznie podobną koncepcję). Zatem baza danych może przechowywać w pamięci pewną liczbę zapytań, przygotowanych i gotowych do wykonania. Te zapytania nie muszą być analizowane i będą szybsze. Często uruchamiane zapytania zwykle znajdują się w buforze i nie wymagają analizowania za każdym razem, gdy są używane.

CHYBA ŻE

Ktoś nie używa sparametryzowanych zapytań. W tym przypadku bufor jest nieustannie przepuszczany przez strumień prawie identycznych zapytań, z których każde musi zostać przeanalizowane i uruchomione przez silnik bazy danych, a wydajność spada, ponieważ nawet często uruchamiane zapytania są wielokrotnie ponownie analizowane. dzień. Dostroiłem bazy danych na życie i było to jedno z największych źródeł nisko wiszących owoców.

TERAZ

Odpowiadając na pytanie: JEŚLI zapytanie zawiera niewielką liczbę odrębnych wartości liczbowych, prawdopodobnie nie spowoduje to problemów i może w rzeczywistości w nieskończoność zwiększyć wydajność. JEŚLI jednak istnieją potencjalnie setki wartości, a zapytanie jest często wywoływane, masz zamiar wpłynąć na wydajność systemu, więc nie rób tego.

Tak, możesz zwiększyć bufor SQL, ale zawsze ostatecznie odbywa się to kosztem innych, bardziej krytycznych zastosowań pamięci, takich jak buforowanie indeksów lub danych. Morał, używaj sparametryzowanych zapytań dość religijnie, aby zoptymalizować bazę danych i użyć więcej pamięci serwera na rzeczy, które mają znaczenie ...

mcottle
źródło
8

Aby dodać informacje do Maćka odpowiedz:

Informacje o kulturze aplikacji innej firmy .NET można łatwo zmienić, wywołując funkcję główną zestawu przez odbicie:

using System;
using System.Globalization;
using System.Reflection;
using System.Threading;

namespace ConsoleApplication2
{
  class Program
  {
    static void Main(string[] args)
    {
      Assembly asm = Assembly.LoadFile(@"C:\BobbysApp.exe");
      MethodInfo mi = asm.GetType("Test").GetMethod("Main");
      mi.Invoke(null, null);
      Console.ReadLine();
    }

    static Program()
    {
      InstallBobbyTablesCulture();
    }

    static void InstallBobbyTablesCulture()
    {
      CultureInfo bobby = (CultureInfo)CultureInfo.InvariantCulture.Clone();
      bobby.DateTimeFormat.ShortDatePattern = @"yyyy-MM-dd'' OR ' '=''";
      bobby.DateTimeFormat.LongTimePattern = "";
      bobby.NumberFormat.NegativeSign = "1 OR 1=1 OR 1=";
      Thread.CurrentThread.CurrentCulture = bobby;
    }
  }
}

Działa to tylko wtedy, gdy główna funkcja BobbysApp jest publiczna. Jeśli Main nie jest publiczne, możesz wywołać inne funkcje publiczne.

user1027167
źródło
1
Nie musisz nawet robić tego kodem. Możesz dodać wstrzyknięcie bezpośrednio w ustawieniach regionalnych systemu Windows. Zobacz moją odpowiedź.
Kaspars Ozols
2
Kto może zmienić ustawienia serwera lub kto może wetrzeć taki kod na serwerze? Jeśli ktoś może to zrobić na twoim serwerze, nie potrzebuje SQL Injection, aby zniszczyć dane.
Reza Aghaei
7

Moim zdaniem, jeśli możesz zagwarantować, że parametr, z którym pracujesz, nigdy nie będzie zawierał łańcucha, to jest to bezpieczne, ale i tak bym tego nie zrobił. Zauważysz również niewielki spadek wydajności ze względu na fakt, że wykonujesz konkatenację. Pytanie, które zadam, brzmi: dlaczego nie chcesz używać parametrów?

Maks
źródło
1
Nie chodzi o to, że nie chcę używać parametrów, używam parametrów. Współpracownik napisał taki kod, który zmodyfikowałem tak, aby był dzisiaj sparametryzowany, co skłoniło mnie do zastanowienia się nad tym pytaniem.
johnnyRose
Dobrze. Wspaniały. Zalecane jest używanie parametrów. W ten sposób nie musisz martwić się o takie rzeczy jak sql injection. Również w przypadku tworzenia zapytań dynamicznych można również używać parametrów niezależnie od stopnia złożoności zapytań. Po prostu użyj stylu @ 1 ... @ n podczas ich tworzenia. I dołącz je do zbioru parametrów z żądaną wartością.
Max
@johnyRose Jest jeszcze jeden punkt używania parametrów: programy ewoluują i się zmieniają. Możesz użyć konkatenacji tylko dla stringów, ale nie gwarantuje to, że ktoś zaimplementuje refaktoryzację, która zmieni jakiś typ parametru, i że zmiany mogą wprowadzić lukę SQL Injection.
lerthe61
3

Jest w porządku, ale nigdy nie jest bezpieczne ... a bezpieczeństwo zawsze zależy od danych wejściowych, na przykład jeśli obiektem wejściowym jest TextBox, atakujący mogą zrobić coś podstępnego, ponieważ pole tekstowe może akceptować ciąg, więc musisz wprowadzić jakiś rodzaj walidacji / konwersji aby móc zapobiec niewłaściwemu wprowadzaniu danych przez użytkowników. Ale chodzi o to, że nie jest to bezpieczne. Tak proste.

japzdivino
źródło
To jest jednak ciąg. Mówię o innych typach danych, takich jak liczby całkowite, wartości logiczne lub czasy danych.
johnnyRose
@johnnyRose Tak, widziałem powyżej bardzo ładny przykład, który oznaczyłeś jako odpowiedź od Kaspardsa ... i świetna odpowiedź, ponieważ używa on typu datetime jako przykładu, który jest rzadki. :) Mam nadzieję, że już przekonałeś się, że nie jest bezpiecznie i lepiej używać parametru w jakimkolwiek typie danych
japzdivino
Nigdy nie miałem wątpliwości, że bezpieczniej jest używać parametrów. Moje pytanie dotyczyło implementacji z silnym typem.
johnnyRose
Tak… zgadzam się. i jest to również świetne pytanie, które może pomóc przyszłym czytelnikom :)
japzdivino
-2

Nie, w ten sposób można uzyskać atak polegający na iniekcji SQL. Napisałem stary artykuł po turecku, który pokazuje, jak tutaj . Przykład artykułu w PHP i MySQL, ale koncepcja działa tak samo w C # i SQL Server.

Zasadniczo atakujesz podążając drogą. Rozważmy, że masz stronę, która pokazuje informacje według wartości identyfikatora całkowitego. Nie sparametryzowałeś tego w wartości, jak poniżej.

http://localhost/sqlEnjeksiyon//instructors.aspx?id=24

Okej, zakładam, że używasz MySQL i atakuję w następujący sposób.

http://localhost/sqlEnjeksiyon//instructors.aspx?id=ASCII((SELECT%20DATABASE()))

Zauważ, że tutaj wprowadzona wartość nie jest ciągiem. Zmieniamy wartość char na int używając funkcji ASCII. Możesz osiągnąć to samo w SQL Server używając "CAST (YourVarcharCol AS INT)".

Następnie używam funkcji length i substring, aby znaleźć nazwę bazy danych.

http://localhost/sqlEnjeksiyon//instructors.aspx?id=LEN((SELECT%20DATABASE()))

http://localhost/sqlEnjeksiyon//instructors.aspx?id=ASCII(SUBSTR(SELECT%20DATABASE(),1,1))

Następnie używając nazwy bazy danych, zaczynasz pobierać nazwy tabel w bazie danych.

http://localhost/sqlEnjeksiyon//instructors.aspx?id=ASCII(SUBSTR((SELECT table_name FROM INFORMATION_SCHEMA.TABLES LIMIT 1),1,1))

Oczywiście musisz zautomatyzować ten proces, ponieważ otrzymujesz tylko JEDEN znak na zapytanie. Ale możesz to łatwo zautomatyzować. Mój artykuł pokazuje jeden przykład w watir . Korzystanie tylko z jednej strony i nie sparametryzowanej wartości identyfikatora. Mogę nauczyć się każdej nazwy tabeli w twojej bazie danych. Potem mogę poszukać ważnych stolików. To zajmie trochę czasu, ale jest wykonalne.

Atilla Ozgur
źródło
2
Moje pytanie dotyczy silnie wpisanego języka. Chociaż twoje wyjaśnienie jest świetne dla języków z elastycznym typowaniem, wstrzyknięta wartość jest nadal ciągiem.
johnnyRose
Żadna wprowadzona wartość nie jest liczbą całkowitą. Otrzymujesz znak i zmieniasz go na liczbę całkowitą za pomocą funkcji ASCII MySQL. Robisz to samo w SQL Server używając CAST (YourCharValue AS INT)
Atilla Ozgur
Miałem na myśli coś takiego:public void QuerySomething(int id) { // this will only accept an integer }
johnnyRose
-3

Cóż ... jedno jest pewne: bezpieczeństwo NIE jest w porządku, gdy łączysz ciąg (pobierany przez użytkownika) z ciągiem poleceń SQL. Nie ma znaczenia, czy klauzula where odnosi się do liczby całkowitej lub dowolnego typu; mogą wystąpić zastrzyki.

W SQL Injection liczy się typ danych zmiennej, która służyła do pobierania wartości od użytkownika.

Przypuśćmy, że w klauzuli where mamy liczbę całkowitą i:

  1. zmienną użytkownika jest ciąg. W takim razie ok, nie jest to łatwe do wstrzyknięcia (używając UNION), ale bardzo łatwo jest ominąć za pomocą 'OR 1 = 1' - jak ataki ...

  2. Jeśli zmienna użytkownika jest liczbą całkowitą. Z drugiej strony możemy `` przetestować '' siłę systemu, przechodząc nietypowe testy dużych liczb pod kątem awarii systemu, a nawet ukrytego przepełnienia bufora (na ostatnim ciągu) ...

Może parametry zapytań lub (jeszcze lepiej - imo) procedur składowanych nie są w 100% bezpieczne dla zagrożeń, ale są najmniej wymaganym środkiem (lub podstawowym, jeśli wolisz), aby je zminimalizować.

Andreas Venieris
źródło
Myślę, że mogłeś źle zrozumieć pytanie. Mówię o niezarejestrowanych typów without.
johnnyRose
Cześć JonnyRose ... dzięki za twoją notatkę. Rozumiem twoje pytanie, ale ułożyłem odpowiedź w bardziej ogólnej formie. W przypadku przypadku nie będącego ciągiem znaków sprawdź mój (2) punkt. ;)
Andreas Venieris