Sign in Join
Wiki copytemporary

Secure programming/pl: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: Secure programming/pl

OldNewLine
1+<div style="font-size:1.88em;margin:0.75em 0;">
2+
3+Bezpieczne programowanie
4+
5+</div>
6+
7+## Przedmowa
8+
9+Ta strona wiki jest próbą nauczenia innego podejścia do tworzenia oprogramowania. Strona wykorzystuje bardzo proste przykłady, aby pokazać, że wiele problemów można wykorzystać w celu wykonania ataku bezpieczeństwa na komputer, program lub cały system.
10+
11+Należy pamiętać, że dokument jest tylko początkiem nauki pisania lepszego i nieco bezpieczniejszego kodu, ale nie stanowi kompletnego przewodnika, jak to zrobić. W rzeczywistości jest to tylko krótki przegląd tego, jak musimy widzieć nasz kod i program oraz jak uniknąć wielu typowych problemów, które tam występują.
12+
13+Proszę pamiętać, że ten dokument dotyczy edukacji w celu lepszego kodowania, a nie przewodnika po hakowaniu i łamaniu programów.
14+
15+Możesz być także zainteresowany zasadami [[The Power of 10/pl|The Power of 10]], aby uzyskać bardziej zwięzłą poradę.
16+
17+## Nie ufaj danym wejściowym
18+
19+Podczas tworzenia programu jest prawdopodobne, że będzie on w jakiś sposób wchodził w interakcję z użytkownikiem, nawet jeśli oznacza to jedynie odczytywanie plików w systemie i prezentację danych.
20+
21+Zwykle w szkołach i na uniwersytetach, gdy zaczyna się pisać programy, osoba ta uczy się, jak otrzymywać dane wejściowe, podczas gdy nauczyciele zwykle mówią tej osobie „załóż, że dane, które otrzymujesz, są prawidłowe”. Wtedy zaczynają się problemy:
22+
23+> **Note:** Nie możemy ufać żadnym danym wejściowym, których nie możemy kontrolować, ponieważ ich zawartość jest nieznana i może wykorzystywać lukę w naszym oprogramowaniu.
24+
25+Czytanie z pliku to odczytywanie niezaufanych danych wejściowych, podobnie jak odczytywanie danych wejściowych użytkownika lub akceptowanie danych wejściowych z sieci.
26+
27+### Dlaczego nie mogę ufać danym wejściowym?
28+
29+Aby zrozumieć, dlaczego dane wejściowe są niebezpieczne, najpierw musimy zrozumieć, czym są dane wejściowe.
30+
31+Dane wejściowe mogą pochodzić z naciśnięcia klawisza, ruchu myszy lub kliknięcia przycisku myszy, lub z odczytywania i akceptowania informacji z wielu innych sposobów, takich jak strumień danych lub nawet funkcje systemowe. W rzeczywistości wszystko, co Twój program otrzymuje z zewnątrz, to są dane wejściowe.
32+
33+Nie ma znaczenia, jaki jest rodzaj danych wejściowych: na przykład użytkownik lub inny system może podać nam błędne dane, a przyczyny mogą być celowe lub pomyłka. Nie możesz kontrolować tego wejścia, a głównym powodem jest to, że nie możesz odgadnąć, jakie będą to dane wejściowe.
34+
35+Wynikiem mogą być puste (NULL) „dane”, które podaje nam użytkownik, liczba wykraczająca poza nasz oczekiwany zakres lub większa ilość znaków niż oczekiwaliśmy, a nawet próba zmiany adresu zmiennej, która akceptuje dane wejściowe od użytkownika. Po prostu nie wiemy, jakie dane wprowadzi użytkownik.
36+
37+Każde „niebezpieczne” postępowanie z danymi wejściowymi może spowodować pobranie krytycznych informacji, których użytkownik nie może zobaczyć, lub modyfikację danych, do której użytkownik nie jest upoważniony, uszkodzenie danych, a nawet uszkodzenie (zawieszenie) samego programu.
38+
39+### Jakich problemów możemy się spodziewać?
40+
41+Przy każdym typie błędu prawdopodobnie znajdziesz inny sposób ataku, ale chciałbym podać krótką listę bardzo powszechnych rodzajów ataków, zamiast opisywać wiele ich typów.
42+
43+Najczęstsze rodzaje ataków to:
44+
45+#### Przepełnienie bufora
46+
47+Gdy otrzymane dane przepełnią ilość pamięci, która została dla nich przydzielona:
48+
49+``` pascal
50+var
51+ iNums : array [0..9] of integer;
52+ ...
53+ FillChar (iNums[-1], 100, #0);
54+ ...
55+ for i := -10 to 10 do
56+ readln (iNums[i]);
57+ ...
58+```
59+
60+Na tym przykładzie widać, że dla statycznej tablicy iNums daliśmy możliwość przyjęcia tylko 10 liczb, podczas gdy potem próbujemy wprowadzić 21 liczb.
61+
62+Należy pamiętać, że chociaż kompilator może ostrzegać w prostych przypadkach, to nie zawsze będzie on reagował w bardziej rozbudowanych formach.
63+
64+Jeśli użytkownik może wprowadzić dane, które są wysyłane do bufora, może on podać pewne wartości, które można zinterpretować jako instrukcje kodu maszynowego, a te zostaną zapisane poza naszym buforem. Komputer mógłby wtedy wykonać ten kod zamiast kodu, który powinien tam być. To jest własnie przepełnienie bufora.
65+
66+#### Atak DoS
67+
68+Denial of Service to nie tylko problem sieciowy, ale może istnieć również na wiele innych sposobów:
69+
70+``` pascal
71+procedure Recurse;
72+begin
73+ while (True) do
74+ begin
75+ Recurse;
76+ end;
77+end;
78+```
79+
80+Ta procedura będzie działać, dopóki system nie wyczerpie zasobów, ponieważ przy każdej rekursji przydziela więcej pamięci stosu i spowoduje, że system przestanie odpowiadać, a nawet ulegnie awarii. Chociaż niektóre systemy – takie jak Linux – będą próbowały dać ci możliwość zaprzestania uruchamiania programu, zajmie ci to dużo czasu.
81+
82+Należy pamiętać, że jest to tylko statyczny przykład, ale przeprowadziliśmy atak DoS na system uruchamiając ten kod.
83+
84+Innym znanym atakiem DoS jest brak zwolnienia zasobów systemowych, takich jak pamięć, gniazda, deskryptory plików itp.
85+
86+Na przykład:
87+
88+``` pascal
89+...
90+ begin
91+ while True do
92+ begin
93+ Getmem(OurPtr, 10);
94+ OurPtr := Something;
95+ end;
96+ end.
97+```
98+
99+Ten przykład pokazuje alokację pamięci (Getmem jest jak malloc w C: rezerwuje pamięć do jakiegoś użycia), ale kończymy wykonywanie kodu bez zwalniania pamięci pod koniec jej używania.
100+
101+#### Wstrzyknięcia
102+
103+Kiedy użytkownik podaje nam dane wejściowe, a my pracujemy na danym wejściu bezpośrednio bez oczyszczania go, użytkownik może umieścić coś w niektórych tagach SQL lub kodzie (takim jak kod skryptu lub kod maszynowy), co sprawi, że nasz program będzie wykonywał pewne dodatkowe działania (np. usunięcie niektórych rekordów/tabeli, wysłanie użytkownikowi pewnych zastrzeżonych danych, takich jak struktura bazy danych/tabeli, użytkownik bazy danych i hasło, zawartość katalogu lub pliku, a nawet uruchomienie programu na komputerze).
104+
105+Przykład wstrzyknięcia SQL:
106+
107+Dane wejściowe użytkownika: Podaj swoje imię i nazwisko: a' OR 1=1
108+
109+Wewnątrz kodu:
110+
111+``` pascal
112+...
113+Write('Proszę, wpisać swoje imię: ');
114+ReadLn(sName);
115+Query1.SQL.Add('SELECT Password FROM tblUsers WHERE Name='#32 + sName + #32);
116+...
117+```
118+
119+Przesłanie tej instrukcji SQL jako danych wejściowych użytkownika spowoduje, że nasze zapytanie doda „ OR 1=1” do instrukcji SQL przekazanej do bazy danych: w tym przypadku zawsze skutkuje to prawdą, a użytkownik uzyskał nieautoryzowany dostęp do programu.
120+
121+## Dostęp do Twoich danych i modyfikacja
122+
123+Nie tylko Twój program będzie miał dostęp do danych, z których korzysta. Jeśli przechowujesz dane w plikach lub (zdalnych) bazach danych, atakujący może uzyskać do nich dostęp za pośrednictwem systemu operacyjnego (i/lub bazy danych i/lub warstwy sieci/protokołu bazy danych).
124+
125+### Szyfrowanie: czy to wystarczy?
126+
127+Aby przeciwdziałać opisanemu powyżej wątkowi, programiści często stosują szyfrowanie. Szyfrowanie może służyć do zapewnienia:
128+
129+- ochrony poufności danych
130+- niezaprzeczalności (to dane stworzone przez osobę, która je stworzyła) i integralności (czy dane są niezmienione) (za pomocą dodatkowych mechanizmów, takich jak podpisy cyfrowe/haszowanie)
131+
132+zarówno dla
133+
134+- przekazywania danych
135+- przechowywania/odzyskiwania danych
136+
137+Jeśli korzystasz z tych metod, Twoje dane nie są jednak automatycznie bezpieczne.
138+
139+Istnieje wiele możliwych ataków na zaszyfrowane dane:
140+
141+- atak na niezabezpieczone algorytmy lub implementację (np. przy użyciu ataku ze znanym tekstem jawnym)
142+- atak na klucze szyfrujące (np. poprzez odwrotną inżynierię Twojego programu, np. jeśli przechowuje klucze w pliku lub w sobie, lub poprzez łatanie programu, aby przechwycił klucze/hasła szyfrujące wprowadzane przez użytkownika).
143+
144+Jeśli nie wiesz dokładnie, co robisz (i nie będziesz wiedzieć, chyba że masz przeszkolenie kryptograficzne), użyj (w kolejności malejącej preferencji):
145+
146+- dobrze znane biblioteki, które są utrzymywane/łatane (np. wbudowane biblioteki FPC i biblioteki takie jak DCPCrypt lub biblioteki zewnętrzne, takie jak openssl lub cryptlib), które używają dobrze znane/powszechnie używane protokoły, i które używają dobrze znane/powszechnie używane algorytmy
147+ - Użyj np. zaufane uwierzytelnianie/SSPI dla połączeń z bazą danych SQL Server/Firebird, aby uniknąć wysyłania haseł przez sieć (Firebird 2 i niższe: w postaci zwykłego tekstu!) i polegać na bezpieczeństwie systemu operacyjnego do uwierzytelniania.
148+ - użyj cryptlib lub openssl z Synapse do wdrożenia SSL/TLS zamiast rozwijania własnego rozwiązania
149+- dobrze znane/powszechnie używane protokoły/API zamiast rozwijania własnych. Protokoły te muszą wykorzystywać dobrze poznane/szeroko stosowane algorytmy kryptograficzne/haszujące. Przykłady:
150+ - GPG/PGP
151+ - TLS (SSL) z PKI/CA (najlepiej nie ufaj tylko tym urzędom, których potrzebujesz i wykonuj uwierzytelnianie za pomocą certyfikatu klienta, jeśli wymaga tego analiza zagrożeń)
152+ - SSH (np. z uwierzytelnianiem klucza publicznego/prywatnego, w razie potrzeby wzmocniony hasłami do kluczy)
153+ - w systemie Windows użyj interfejsu API, aby uzyskać aktualnie uwierzytelnionego użytkownika. Jeśli wymuszasz odpowiednie zabezpieczenia systemu operacyjnego (długość hasła, zmiany, dostęp fizyczny itp.), nie musisz zarządzać własnym mechanizmem ogsługi nazwy użytkownika/hasła na poziomie aplikacji.
154+- dobrze poznane algorytmy kryptograficzne/haszujące (takie jak AES/Rijndael, 3DES i SHA512). Zachowaj ostrożność w zakresie akceptowanych algorytmów (np. MD5 jest niezabezpieczony do podpisywania wiadomości).
155+
156+Szyfrowanie jest częścią zestawu możliwych środków bezpieczeństwa; wysiłek/pieniądze na to wydane powinny zostać ocenione w ramach analizy bezpieczeństwa (patrz poniżej).
157+
158+## Mity i założenia
159+
160+Wiele problemów związanych z bezpieczeństwem wynika z ignorowania ważnych ostrzeżeń i informacji przekazanych przez kompilator oraz z myślenia, że ​​program nie zawiera żadnego możliwego do wykorzystania problemu.
161+
162+Oto kilka przykładów tego typu problemów:
163+
164+### mity
165+
166+- Bezpieczeństwo przez ukrycie – Gdy nikt nie wie o problemie, nikt nie może z niego skorzystać; np. użyj niejasnej nazwy kolumny do przechowywania haseł w swojej bazie danych.
167+- Bezpieczny język programowania – Istnieją języki takie jak Perl, które wielu ludzi uważa za bezpieczne przed przepełnieniem bufora i innymi lukami, choć nie jest to prawdą.
168+- Hasło haszowane jest bezpieczne — plik z haszowanym hasłem nie jest bezpieczny. Hash może odpowaidać tylko jednej wartości i nie można odzyskać oryginalnych danych. Ale „zahaszowane hasło może zostać odzyskane za pomocą ataku typu brute force lub tęczowej tablicy i dlatego wymaga użycia soli lub wielu rund haszujących”: --BigChimp 16:19, 24 July 2011 (CEST)''
169+- Nic nie może zepsuć mojego programu – przekonanie, że jesteś jedynym programistą na świecie, który pisze bezbłędny kod, jest prawdopodobnie zbyt optymistyczne. Może masz szczęście i po prostu piszesz kod, który nie działa poprawnie bez luk w zabezpieczeniach, które można wykorzystać...
170+
171+### założenia
172+
173+- Zespół QA znajdzie i naprawi moje błędy bezpieczeństwa.
174+- Użytkownik (lub ktoś inny) nie zaatakuje mojego programu i jego danych.
175+- Mój program będzie używany tylko do pierwotnego użytku.
176+- Wszystkie wyjątki mogą pozostać nieobsłużone.
177+
178+## Analizuj, aby zrozumieć zagrożenia i bezpieczeństwo
179+
180+Generalnie programista (lub jego pracodawcy/właściciele firmy) powinien przeprowadzić analizę wszystkich zagrożeń (od fizycznego dostępu/ataku po ataki logiczne i socjotechniczne) dla całego systemu (w tym infrastruktury – OS, bazy danych, sieci a także fizycznej maszyny/okablowanie/budynki/połączenia zewnętrzne), aby przeanalizować, czy nie pozostawiasz otwartej luki w zabezpieczeniach, która jest niedopuszczalna (z perspektywy ryzyka/korzyści).
181+
182+Zakres analizy powinien zależeć od wartości danych/procesów chronionych przez system. Oczywiście nie ma sensu szaleć, próbując przeanalizować fizyczne bezpieczeństwo swojego domu podczas opracowywania programu hobbystycznego, aby śledzić wyniki brydżowe.
183+
184+Korzyści z tego rodzaju analiz:
185+
186+- zagrożenia pozostające po ogłoszeniu lub ujawnieniu środków bezpieczeństwa. Często toczy się dyskusja na temat prawdopodobieństwa wystąpienia tego ryzyka lub związanego z nim wpływu, ale fakt, że istnieje jakiś potencjalny wektor ataku sprawia, że jest on przynajmniej jasny i można podejmować decyzje na podstawie tych informacji
187+- dość łatwo można zobaczyć, jakie środki bezpieczeństwa są przeprojektowane („zbyt bezpieczne”, marnotrawstwo pieniędzy) lub niedopracowane („niewystarczająco bezpieczne”). Jeśli nie możesz teraz wykorzystać tych informacji, możesz przynajmniej uczyć się z nich dla innych projektów, w tym przyszłej konserwacji/modyfikacji programu
188+
189+## Konkretne rozwiązania
190+
191+Skoro znamy już pewne problemy, które możemy napotkać podczas tworzenia programów, powinniśmy dowiedzieć się, jak je naprawić. Wszystkie problemy, które widzieliśmy powyżej, przejawiają się w dwóch typach: założenia i brak starannego programowania. A żeby nauczyć się je naprawiać, najpierw musimy nauczyć się myśleć w inny sposób niż dotychczas.
192+
193+### Przepełnienie
194+
195+Aby naprawić przepełnienie danych, takie jak bufory i inne rodzaje danych wejściowych, musimy przede wszystkim zidentyfikować rodzaj danych, z którymi musimy pracować.
196+
197+#### Przepełnienie bufora
198+
199+Jeśli wrócimy do naszego przykładu:
200+
201+``` pascal
202+var
203+ iNums: array [0..9] of Integer;
204+ ...
205+ FillChar(iNums[-1], 100, #0);
206+ ...
207+ for i := -10 to 10 do
208+ ReadLn(iNums[i]);
209+ ...
210+```
211+
212+Widzimy tutaj zakres, który został przepełniony naszymi wartościami, nawet nie sprawdzając, czy numer indeksu jest poprawny.
213+
214+W tablicach dynamicznych/otwartych w Pascalu możemy poznać limity przydzielonej pamięci. Więc wszystko, co musimy zrobić, to sprawdzić, czy rozmiar nie jest za mały lub za duży dla naszego bufora i ograniczyć akceptację do rozmiaru, jaki sobie życzymy.
215+
216+Zatem przykład należy zmienić na:
217+
218+``` pascal
219+var
220+ iNums: array [0..9] of Integer;
221+
222+ ...
223+ FillChar (iNums[Low(iNums)], High(iNums), #0);
224+ ...
225+
226+ for i := Low(iNums) to High(iNums) do
227+ ReadLn(iNums[i]);
228+ ...
229+```
230+
231+Ale czekaj, coś jest jeszcze nie tak!
232+
233+Readln przyjmie nieograniczoną ilość znaków i nikt nam nie obiecuje, że będzie to liczba całkowita lub nawet z zakresu, który możemy obsłużyć.
234+
235+#### Przepełnienie liczby
236+
237+Podczas gdy łańcuch w Pascalu jest czystą tablicą (hrmm hrmm.. niezupełnie, przynajmniej nie w FPC, ale załóżmy przez chwilę, że jest, OK?), więc *readln* spróbuje znaleźć i zobaczyć, jakie są jego limity i czy nie spróbujemy przekroczyć zakresu, który nadaliśmy temu typowi, ale liczby nie są takie same.
238+
239+Liczby mają ograniczenia, komputer/kompilator ma wiele ograniczeń dotyczących pamięci i liczb. Może dać tylko „małą” ilość pamięci na liczby (liczby zmiennoprzecinkowe i całkowite). I w większości przypadków nie potrzebujemy uzywać dużego zakresu liczb (jak zmienna logiczna, która zwykle potrzebuje tylko dwóch liczb).
240+
241+W powyższym przykładzie możemy mieć przepełnienie bufora, które spowoduje błąd sprawdzania zakresu, który da nam złą liczbę (problemy z przypomnieniem Carry Flag (flaga przeniesienia)... nie będę ich tutaj wyjaśniać), a także mamy efekt DoS, ponieważ nasz program zatrzyma się w tym momencie.
242+
243+Więc co możemy zrobić, aby to naprawić?
244+
245+Przede wszystkim możemy chcieć pracować ze zmienną łańcuchową, która będzie odpowiadała największej długości liczby +1 (dla znaku minus) lub możemy stworzyć własną procedurę/funkcję readln, która będzie specjalizować się w typie integer.
246+
247+Dla pierwszej opcji możemy wykonać następujące czynności (skopiowane z dokumentacji FPC):
248+
249+``` pascal
250+Program Example74;
251+
252+{ Program do demonstracji funkcji Val. }
253+Var
254+ I, Code: Integer;
255+begin
256+ Val(ParamStr(1), I, Code);
257+ If Code <> 0 then
258+ Writeln('Błąd na pozycji ', code, ' : ', Paramstr(1)[Code])
259+ else
260+ Writeln('Wartość : ', I);
261+end.
262+```
263+
264+Tutaj widzimy, jak przekonwertować łańcuch na liczbę całkowitą z bardzo łatwą obsługą błędów. Funkcja *StrToInt* także może załatwić sprawę, ale wtedy musimy przechwycić wyjątek w przypadku obsługi błędów.
265+
266+Oto mały przykład małej procedury typu *readln* dla liczb całkowitych.
267+
268+``` pascal
269+program MyReadln;
270+uses
271+ CRT;
272+
273+procedure MyIntReadLn(var Param: Integer; ParamLength: Integer);
274+var
275+ Line: string;
276+ ch: char;
277+ Error: Integer;
278+begin
279+ Line := '';
280+
281+ repeat
282+ ch := ReadKey;
283+ if (Length (Line) <> ParamLength) then
284+ begin
285+ if (ch in ['0'..'9']) then
286+ begin
287+ Line := Line + ch;
288+ write (ch);
289+ end
290+ else
291+ if (ch = '-') and (Length(Line) = 0) then
292+ begin
293+ Line := '-';
294+ write (ch);
295+ end;
296+ end;
297+
298+ if (ch = #8) and (Length(Line) <> 0) then // backspace
299+ begin
300+ Line := Copy(Line, 1, Length(Line) - 1);
301+ gotoxy(WhereX - 1, WhereY);
302+ write(' ');
303+ gotoxy(WhereX - 1, WhereY);
304+ end;
305+ until (ch = #13);
306+
307+ val(Line, Param, Error);
308+
309+ if (Error <> 0) then
310+ Param := 0;
311+
312+ writeln;
313+end;
314+
315+var
316+ Num : Integer;
317+begin
318+ Write('Number: ');
319+ MyIntReadLn(Num, 2);
320+ WriteLn('The number is: ', Num);
321+end.
322+```
323+
324+Pamiętaj, że możesz uczynić go jeszcze lepszym i bardziej wydajnym, jeśli chcesz. To tylko bardzo mały przykład pokazujący, jak to zrobić.
325+
326+#### Jakie są zagrożenia bezpieczeństwa w Przepełnieniach?
327+
328+Przepełnienie pamięci może pozwolić na wykonanie dowolnego kodu procesora, a użytkownicy mogą uruchamiać dowolny typ kodu i nic nie może ich powstrzymać.
329+
330+### Blokada usług DoS
331+
332+Blokada usług (DoS) to jeden z najtrudniejszych rodzajów ataków, którym należy zapobiec. Powody to:
333+
334+- Blokada usług może być wykonana nawet bez błędów, które można wykorzystać, na przykład przy użyciu programu „ping” na wielu komputerach w celu DoS komputera podłączonego do Internetu.
335+- Każdy zasób systemowy może być ofiarą DoS, taką jak otwieranie gniazd, odczytywanie plików lub przydzielanie pamięci.
336+- Usunięcie plików takich jak moduł jądra może spowodować duży problem. *Nie rozumiem tego wiersza --BigChimp 19:32, 24 lipca 2011 (CEST)*
337+- Brak konfiguracji lub niewłaściwa konfiguracja może również spowodować blokadę usług, jeśli pozwala to na niewłaściwe wykorzystanie wrażliwych zasobów.
338+- Za dużo uprawnień lub ich brak *Nie rozumiem. Niewystarczająca liczba uprawnień może stanowić problem. Ale za dużo? To oczywiście zagrożenie bezpieczeństwa, ale nie problem DoS. --[[Użytkownik:BigChimp|BigChimp]] 19:32, 24 lipca 2011 r. (CEST)*.
339+- Prawie każdy rodzaj exploita może spowodować blokadę usług.
340+
341+Jak widać, blokada usług może być prawie wszystkim, co może uniemożliwić systemowi działanie tak, jak powinien, z powodu wykorzystania błędów lub błędnego kodu lub po prostu wadliwego programu, który przechwytuje zasoby systemowe.
342+
343+W powyższym przykładzie DoS:
344+
345+``` pascal
346+procedure Recurse;
347+begin
348+ while (True) do
349+ begin
350+ Recurse;
351+ end;
352+end;
353+```
354+
355+Stworzyłem również przepełnienie stosu (inny rodzaj przepełnienia bufora), który spowodował, że komputer potrzebował więcej zasobów pamięci, aby kontynuować wykonywanie kodu.
356+
357+Każdy zasób systemowy, który jest dostępny dla programu, może zostać nadużyty, nie zwracając go z powrotem do systemu, gdy program „już go nie potrzebuje”. Przetrzymywanie zasobów systemowych, takich jak pamięć lub gniazda, blokuje innym programom możliwość wykonywania niektórych z ich działań. W ten sposób większość programów zatrzyma wykonywanie i zgłosi błąd, a niektóre będą się zawieszać i nadal szukać zasobów systemowych.
358+
359+Należy pamiętać, że niektóre nadużycia zasobów systemowych wynikają z błędu w programowaniu, jak oczekiwanie na bufor 150k, podczas gdy rzeczywisty bufor ma tylko 2 bajty, a gdy program nadal szuka bufora 150k, nowe żądanie tworzy kolejny bufor 150k itd., dopóki system nie będzie już w stanie odpowiedzieć na żadne z żądań (jest to znany typ ataku).
360+
361+Dobrym obejściem tego błędu jest ograniczenie liczby niepełnych buforów, które można przydzielić jednocześnie. Jeśli bufor nie jest pełny po upływie limitu czasu, powinien być wolny. Jednak to rozwiązanie spowoduje również odmowę usługi, ponieważ komunikacja i tak zostanie zatrzymana w pewnym momencie lub powolne połączenie może spowodować utratę danych.
362+
363+### Wstrzykiwanie
364+
365+Istnieje wiele sposobów na wstrzyknięcie pewnego rodzaju kodu do naszych programów. Jak widzieliśmy na powyższym przykładzie:
366+
367+Dane wejściowe użytkownika: Podaj swoje imię i nazwisko: a' LUB 1=1
368+
369+Wewnątrz kodu:
370+
371+``` pascal
372+...
373+write('Proszę wpisać swoje imię: ');
374+readln(sName);
375+Query1.SQL.Add('SELECT Password FROM tblUsers WHERE Name='#32 + sName + #32);
376+...
377+```
378+
379+Wstrzyknięcie nastąpiło, ponieważ nie filtrujemy (nie odkażamy) naszego kodu: oznacza to sprawdzenie, czy otrzymujemy dokładnie taki rodzaj wejścia, jakiego szukamy, i nic więcej.
380+
381+Na przykład możemy sprawdzić, czy *sName* zawiera spacje. Jeśli tak, nie kontynuuj sprawdzania reszty zmiennej. To pomaga, jeśli nazwa użytkownika może składać się tylko z jednego słowa składającego się z liter, może znaku apostrofu (`'`) i może nawet podkreślenia (`_`) i na tym koniec. Jeśli wprowadzimy liczbę, powinno to być nielegalne (chyba że chcemy używać „języka hackerskiego” (fonetycznie) lub zezwolić na używanie cyfr.
382+
383+Istnieje wiele sposobów oczyszczenia danych. Mniej skuteczny (ale często używany) to:
384+
385+#### Nieskuteczne odkażanie
386+
387+``` pascal
388+function ValidVar (const S: AnsiString; AllowChars: TCharset): Boolean;
389+var
390+ i: Word;
391+begin
392+ i := 0;
393+ Result := True;
394+
395+ while (Result) and (i <= Length(S)) do
396+ begin
397+ Inc(i);
398+ Result := S[i] in AllowChars;
399+ end;
400+end;
401+```
402+
403+Funkcja zwraca wartość true, jeśli mamy poprawną strukturę treści podaną przez parametr *AllowChars* w zmiennej *S*. Należy pamiętać, że ta funkcja jest tylko próbką koncepcji i może wymagać więcej pracy, aby mogła zostać w pełni wykorzystana.
404+
405+Innym sposobem na zrobienie tego samego jest użycie wyrażeń regularnych w następujący sposób (jest to próbka koncepcji wzięta z języka Perl. FPC nie ma w pełni obsługiwanego silnika wyrażeń regularnych, który umożliwia modyfikację ciągów):
406+
407+`$sName =~ s/[^a-z0-9_\']//gi;`
408+
409+Wyrażenie regularne usuwa wszelkie niepoprawne znaki z łańcucha i zwraca do nas usunięty łańcuch. Zwróć uwagę, że o ile wiem, to wyrażenie regularne będzie działać również w silnikach ereg, ale z minimalnymi korektami (flaga *g* instruuje Perla, aby zastąpił wszystkie znalezione pasujące wzorce, a *i* oznacza *case insensitivity* (niewrażliwość na wielkość liter)).
410+
411+Teraz, gdy wiemy, że nasze dane wejściowe są prawidłowe, musimy zobaczyć, do czego służy zawartość zmiennej. Jeśli zawartość zmiennej trafia do bazy danych, skryptu cgi lub czegokolwiek innego, co ma własną składnię, musimy zmienić treść zgodnie z niedozwolonymi lub kontrolnymi znakami odpowiedniego języka (np. SQL dla baz danych).
412+
413+Istnieje wiele sposobów na uniknięcie tego typu zawartości. Załóżmy na razie, że ta treść trafia do zapytania bazy danych. Teraz przede wszystkim musimy upewnić się, że nasz dodatkowy znak ucieczki, nie zwiększy rozmiaru naszych danych, powyżej limitu długości pól w naszej bazie danych. Ponieważ, jeśli tak się stanie, możemy doprowadzić do wstrzykiwania, do utraty danych, blokady usług lub przepełnienia bufora (poważna baza danych zwykle obcina dane, ale czasami nie we właściwym miejscu).
414+
415+Zwykle jedyną ucieczkę, jaką musimy zrobić, aby użyć ciągu w bazie danych, jest ucieczka jedynie znaku apostrofu (') (chociaż niektóre bazy danych mogą mieć problemy z większą liczbą znaków niż apostrof). Tak więc wszystko, co powinniśmy zrobić, to reprezentować apostrofy w sposób, który nie wpłynie na silnik bazy danych, jak znak odwrotnego ukośnika (\\') lub podwajać każdy apostrof do dwóch apostrofów (''), a może nawet użyć innego znaku, który zastąpi apostrofy w zapytaniu i zamienić je ponownie, gdy musimy pokazać je użytkownikowi.
416+
417+#### Ograniczanie wprowadzania przez parametry zapytania SQL
418+
419+Obowiązkowa [ilustracja wizualna](https://xkcd.com/327/).
420+
421+Po upewnieniu się, że przestrzegamy ograniczeń, możemy kontynuować nasze próby. Aby uciec od kodu, możemy użyć kilku podejść. Mniej przyjazny dla debugowania sposób, ale pewny sposób na poprawną ucieczkę, to użycie techniki parametrów:
422+
423+``` pascal
424+Query1.SQL.Add('SELECT Password FROM tblUsers WHERE Name=?');
425+Query1.Parameters.Add(sName);
426+if (Query1.Execute) then
427+...
428+```
429+
430+Ta technika pozwala silnikowi bazy danych uciec przed parametrem w taki sposób, abyśmy mogli korzystać z zawartości bez żadnych problemów związanych z niedozwolonymi znakami. Ponadto niektóre bazy danych mają zwiększoną wydajność w przypadku powtarzających się wywołań tego kodu, ponieważ mogą one przygotować do tego instrukcję wewnętrzną z parametrami. Wadą jest to, że nigdy nie możemy debugować wyniku zapytania. Oznacza to, że nie możemy zobaczyć, w jaki sposób zawartość *sName* osadzona jest w instrukcji SQL i nigdy nie możemy z tego powodu sprawdzić, czy nasze zapytanie było poprawne.
431+
432+Jednak po przetestowaniu zapytania bez parametrów dodawanie parametrów jest dość łatwe, więc w praktyce ten problem nie jest tak duży, jak się wydaje.
433+
434+### Wydajny kod
435+
436+Wspomniane powyżej środki bezpieczeństwa komplikują kod, jeśli użyłeś najbardziej wydajnego kodu, aby uzyskać potrzebną funkcjonalność. Na szczęście czasami możesz przekazać komplikacje kodu do frameworka/biblioteki, która się tym zajmuje. Na przykład: w przykładzie SQL DoS możesz pozwolić silnikowi bazy danych zająć się ucieknięciem danych za pomocą sparametryzowanych zapytań, przy niewielkim dodatkowym koszcie konieczności użycia parametrów w kodzie.
437+
438+Jednak pisanie wydajnego, ale podatnego na zagrożenia kodu nie pomaga nikomu poza prawnikami od odpowiedzialności cywilnej i ekspertami kryminalistyki.
439+
440+## Poza tym dokumentem
441+
442+O ile w tym dokumencie podałem kilka krótkich (tak, wiem, że to niedopowiedzenie 😉) przykładów i informacji o tym, jak stworzyć lepszy kod, o tyle jest wiele kwestii, których nie poruszyłem w tym dokumencie. Część z nich to uprawnienia użytkownika do uruchamiania programów, rootkity systemu i inne problemy, które nasz kod musi wziąć pod uwagę (zmienna środowiskowa to tylko jeden przykład).
443+
444+Przeczytaj więcej artykułów dotyczących problemów z bezpieczeństwem, takich jak
445+
446+Przepełnienia bufora:
447+
448+- <http://www.securiteam.com/securityreviews/5QP0L0AFFS.html>
449+- <http://www.securiteam.com/securityreviews/5OP0B006UQ.html>
450+- <http://www.securiteam.com/securityreviews/5IP0G1P8AM.html>
451+- <http://www.securiteam.com/securityreviews/6Q00L00BFI.html>
452+- <http://www.securiteam.com/securityreviews/5UP0B0A60Y.html>
453+
454+Blokada usług (DoS):
455+
456+- <http://www.securiteam.com/securityreviews/5AP0V0AA1W.html>
457+- <http://www.securiteam.com/securityreviews/6Z00T0K95O.html>
458+
459+Wstrzykiwanie SQL:
460+
461+- <http://www.securiteam.com/securityreviews/5DP0N1P76E.html>
462+- <http://www.securiteam.com/securityreviews/5UP010A6AA.html>
463+- <http://www.securiteam.com/securityreviews/5GP0E2K7FO.html>
464+
465+---
466+*From the Free Pascal wiki, page "Secure programming/pl", as it stood on 2022-10-02 after a change by Slawek, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
467+Category: Code

Back to history