Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: SQL Injection/Insertion
Forum PHP.pl > Forum > PHP
Stron: 1, 2, 3, 4, 5, 6, 7, 8, 9
Jarod
Cytat(eai @ 2.08.2006, 21:40 ) *
@J4r0d Przecież to jest jeszcze prostsze smile.gif

Przykład:

checksum.php
  1. <?php
  2.  
  3. function checksum ($id) {
  4. return substr(md5('aXq23' . $id), 1, 3); 
  5. }
  6.  
  7. ?>


admin.php
  1. <?php
  2.  
  3. //...
  4.  
  5. include 'checksum.php';
  6. function foo () { //Jakas tam funkcja generujaca linki do panelu admina bla bla bla...
  7. $row = ...; //Tablica np. wynik z mysql
  8. echo 'strona.com?usun=' . $row['id'] . '&checksum=' . checksum($row['id'];
  9.  }
  10.  
  11.  
  12. function delete () {
  13. if(checksum ($_GET['id']) == $_GET['checksum']) {
  14.  
  15. // Usuwasz
  16.  
  17. }
  18. }
  19.  ?>


Prościej się wytłumaczyć nie da smile.gif

Dzięki. Nie zauważyłem, że generujesz go na podstawie Id. Wszystko jasne. Dzięki.
planet_x
Co do zabezpieczenia przed SQL Injection znalazłem coś takiego

  1. <?php
  2.  
  3. $arrArguments = array();
  4. $intArgumentIndex = 0;
  5.  
  6. function parseArgument($arrMatches) {
  7. global $arrArguments, $intArgumentIndex;
  8.  
  9. $strMatch = $arrMatches[0];
  10. $strArgument = @$arrArguments[$intArgumentIndex++];
  11. switch ($strMatch) {
  12. case '%d': return (int)$strArgument;
  13. case '%s': return '"'.
  14. mysql_real_escape_string($strArgument).'"';
  15. case '%b': return (int)((bool)$strArgument);
  16. }
  17. }
  18.  
  19. function SQL($strSql) {
  20. global $arrArguments, $intArgumentIndex;
  21.  
  22. $arrArgs = func_get_args();
  23. array_shift($arrArgs);
  24. $arrArguments = $arrArgs;
  25. $intArgumentIndex = 0;
  26. return preg_replace_callback('/(%[dsb])/', 'parseArgument',
  27. $strSql);
  28. }
  29.  
  30. ?>


Zastosowanie:
  1. $sql = SQL('INSERT INTO users (id, uid, name, username, password, newsletter)
  2. VALUES (NULL, %d, %s, %s, %s, %B)', $_POST['uid'], $_POST['name'],
  3. $_POST['username'], md5($_POST['password']), $_POST['newsletter']);
  4.  
  5. INSERT INTO users (id, uid, name, username, password, newsletter)
  6. VALUES (NULL, 1, "Łukasz \"anAKiN\" Lach", "anakin",
  7. "97296eca657a093aa379778c237e292d", 1)


Cały temat pod http://www.hacking.pl
oraz bardzo dobry przykład po angielsku ale kod każdy rozumie
http://www.unixwiz.net/techtips/sql-injection.html
a tu przykład błedów wysyłanych przez formularz
http://webcity.pl/webcity/porady.php/t/113

Dobrym też pomysłem są logi jeżeli było jakieś błędne zapytanie, dzięki temu można wyczaić co dany klient kombinuje, i powiedzmy przyblokować w imie dobra jego IP na jakiś czas ewentualnie login, wtedy niezrobimy krzywdy innym userom na tym samym ip.

Co do tego usówania to ja jeszcze weryfikuje IP, nazwe sesji, sumę kontrolną, i uprawniemia usera, pozatym nie jest dany wpis wywalany z bazy tylko deaktywowany powiedzmy jakieś pole w DB odpowiada za status, pużniej odpalam co jakiś czas skrypt który usówa wpisy starsze niż 30 dni z bazy danych w celu odciążenia serwera. Myślę że to w miarę bezpieczna metoda jeżeli chodzi o usówania damych z bazy. i jeszczcze na dodatek jak jest kilka osób które zarządzają serwisem.
php programmer
Mam zapytanie, które jest brzydkie

  1. <?php
  2. $query = "DELETE FROM newsy WHERE id=".$_GET['id'];
  3. ?>


Czy jak zmienie w taki sposób:

  1. <?php
  2. $query = "DELETE FROM newsy WHERE id='".$_GET['id']."'";
  3. ?>


To będzie już ładne questionmark.gif?
nospor
a jak ktos ci w miejsce id zamiast powiedzmy 2, wpisze: 2' or 1=1 to usunie ci wszystko z tabeli.... byla mowa na poczatku tego topicu. jesli id to liczba, to rzutuj ja na liczbe: (int)$_GET['id']. jak nie liczba to slashuj
php programmer
OK. Ale jak mam już zapytanie typu SELECT, np
  1. <?php
  2. $query = "SELECT * FROM newsy WHERE id=".$_GET['id'];
  3. ?>

To rozumiem, że chyba nic złego się nie może stać ?
nospor
W przypadku mysql za bardzo tak ci nic nie skasuja, gdyz mysql_query pozwala na wykonanie tylko jednego zapytania. ale w przypadku innych baz to moglbys sie zzdziwic.
Pozatym w mysql to ci moga wyciagnac inne dane niz w twoim warunku, wystarczy ze za id dadza: 2 or 1=1
i juz poznaja wszystkie rekordy a nie tylko o danym id.

Przyjmij wkoncu do wiadomosc. Dane nalezy filtrowac, niezaleznie od tego czy ktos moze zaszkodzic czy nie. Naucz sie wyrabiac w sobie dobre nawyki.
Cos ma byc intem: zrzutuj na int. Cos ma byc tekstem: przeslashuj to
sobstel
Cytat(php programmer @ 21.08.2006, 14:05 ) *
OK. Ale jak mam już zapytanie typu SELECT, np
  1. <?php
  2. $query = "SELECT * FROM newsy WHERE id=".$_GET['id'];
  3. ?>

To rozumiem, że chyba nic złego się nie może stać ?


żartujesz czy to jakaś prowokacja? w $_GET['id'] wpisuje OR 1=1 i po sprawie. wlasciwie mozna zrobic tu wszystko teraz. taki przyklad pojawia sie w kazdym kursie, artykule, ksiazce jako calkowity brazk zabezpieczenia.
skowron-line
Cytat(nospor @ 21.08.2006, 12:08 ) *
mysql_query pozwala na wykonanie tylko jednego

a jesli bedzie cos takiego
http://index.php?site=del&id=2
i dopiszesz dalej
';%20$mysql_query%20=%20"%20DELETE%20%20FROM%20USERS";
chodzi o usuwanie to czy cos takiego ma szanse zadzialac

w przypadku jak id nie jest filtrowane
nospor
Cytat
a jesli bedzie cos takiego
http://index.php?site=del&id=2
i dopiszesz dalej
';%20$mysql_query%20=%20"%20DELETE%20%20FROM%20USERS";
chodzi o usuwanie to czy cos takiego ma szanse zadzialac

w przypadku jak id nie jest filtrowane

Czy Twoim zamierzeniem bylo zakonczenie jednej instrukcji php i wywolanie drugiej, w tym przypadku wywolanie ponownie mysql_query? Powodzenia życze. winksmiley.jpg
php programmer
Kurcze zrobiłem coś takiego:

  1. <?php
  2. $query = ($_GET['id']=='') ? 'INSERT INTO formularze SET' : 'UPDATE formularze SET ';
  3. $query .= " name = '".mysql_escape_string($_POST['name'])."', date='".$_POST['date']."' ";
  4. if ($_GET['id']!='')
  5. $query .= ' WHERE id ='.(int)$_GET['id'];
  6.  
  7. $result = mysql_query($query) or die(mysql_error());
  8. ?>


Probelm jest chyba z mysql_escape_string
bo teraz po dodaniu tesktu z cudzysłowem i zapisaniu w bazie,
jak robie wyświetlanie wpisanych wartości to mam dodane slashe,
Co się w takim przypadku robi? Jest jakaś funkcja na to?
nospor
no musisz przed wyswietleniem uzyc stripslashes. jest to pewien feler... smile.gif

Mozesz tez zapisywac do bazy przy pomocy htmlspecialchars z dyrektywa ENT_QUOTES. Zapiszesz wowczas encje i nie bedziesz mial \
sobstel
używaj prepared statements to w wiekszosci przypadkow nie bedziesz musial sie sie przejmowaniem slashowaniem i odslashowaniem. niestety dostepne dopiero od mysqli i pdo
free
Cytat(MoD @ 27.02.2005, 16:45:48 ) *
Ja do liczb stosuje najczęściej ereg" title="Zobacz w manualu php" target="_manual (zwłaszcza w UPDATE, w grze MMORPG). Wtedy mam pewność że osoba która wpisze np -1230 nie wyrządzi mi żadnych szkód. A zabezpieczanie skryptów można trenować na wspomnianym przeze mnie wyżej ExoFusion. Jak ktoś go tak zabezpieczy, że nie będzie żadnych (no, może nie żadnych, a prawie żadnych) błędów to będzie się miał czym pochwalić (ja znałem 2 gry na 10 które były w miarę zabezpieczone, ale i tak padły - właśnie przez SQL Injection)

Apropo gier: http://sge.laventhar.pl/ Włamałem sie do niej pół roku temu poprzez błąd serwera, w kodzie php odnalazłem pliki *ini a tam hasło :-) i gra była moja.
Vexator
przyznam szczerze, ze calego topica nie przeczytalem i moze sie juz pojawilo

jesli chcemy zrobic
  1. SELECT pole FROM tabela WHERE id=$_GET['id']

to najlepiej jest nie przesylac zmiennej bezposrednio GETem, czy POSTem, lecz zrobic tak:

  1. <?php
  2.  
  3. switch ($_GET['id'])
  4. {
  5. case 'a': $szukana=0;
  6. break;
  7. case 'b': $szukana=1;
  8. break;
  9. default : $szukana=666;
  10. }
  11.  
  12. $sql = "SELECT pole FROM tabela WHERE id =".$szukana.";";
  13. ?>


w ten sposob nikt nie jest w stanie pod nasza zmienna podpiac "zlych" warunkow do sqla, bo jesli wpisze cokolwiek innego niz a lub b, to $szukana bedzie defaultowa


p.s. co zrobic, zeby forum nie wstawialo mi \ przed "?
nospor
@Vexator z calym szacunkiem, ale przeczytaj jednak ten topic caly, albo przynajmniej strone na ktorej napisales tego posta...
Przeciez ty dales warunek na ID, w bazie mam powiedzmy 1000 rekordow i co, mam walić na kazdego case? Jak ty to sobie wyobrazasz? poroniony pomysl
skoro to ID to wystarczy zrzutowac na int: (int) $_GET['id']
i nikt ci nic nie wrzuci
free
Naklepsza ochroną jest stosowanie sesji z prawami dostepu. W swoich skryptach przed wyslaniem zapytanie do SQL spr czy user ma prawa dostepu, jezeli nie skrypt nie puszcza pasozyda.
nospor
@free ale jak to sie ma do topicu w ktorym uraczyles nas tym postem?
W jaki sposob sprawdzasz czy koles ma prawa? Na podstawie pewnie czy zalogowany, a zeby sie zalogowac to musi wpisac login i haslo i juz w tym momencie moze zrobic ci atak. No chyba ze sprawdzasz czy ma prawa do zalogowania sie winksmiley.jpg

edit: a nawet jak ma prawa to moze chcacy lub niechcacy zrobic cos "źle"
Blastereq
Hmm, mam pytanie, stosuje mod_rewrite w ten sposób :
  1. RewriteEngine on
  2. RewriteRule ^$ /index.php
  3. RewriteRule ^([0-9a-z]+)$ /$1/
  4. RewriteRule ^([0-9a-z]+)/$ /index.php?p_zmienna=$1
  5.  
  6. RewriteRule ^([0-9a-z]+)/([0-9a-z]+)$ /$1/$2/
  7. RewriteRule ^([0-9a-z]+)/([0-9a-z]+)/$ /index.php?p_zmienna=$1&d_zmienna=$2

Adres strony pojawia się w ten sposób : http://strona.net/wartosc1/wartosc2/
Jeśli w żadnym linku nie odwołam się do postaci http://strona.net/index.php?p_zmienna=wart...mienna=wartosc2 . To czy ewentualny atakujący będzię miał możliwość w jakikolwiek sposób zobaczyć nazwę tej zmiennej ? Bo jeśli nie będzie miał możliwości to przy wpisaniu http://strona.net/wartosc1 OR 1=1/ wyskoczy błąd serwera gdyż pusty znak nie jest uwzględniony w [0-9a-z] i SQL Injection się nie powiedzie. Czy się myle ?
Rzast
Ja bronię się trochę inaczej:
robię zapytanie typu
  1. <?php
  2. $sql='SELECT id,login FROM baza WHERE haslo="'.md5($_POST['haslo']).'"';
  3. $wynik=mysql_fetch_row($sql);
  4. if ((mysql_num_rows($sql)==1) && ($wynik[1]==$_POST['login'])){
  5. //Zalogowany
  6. $_Session['id']=$wynik[0];
  7. //Dalsze czynności....
  8. }else{
  9. //Jeszcze raz, bo nie udało się. Można ewentualnie wypisać, czy to zły login, czy 
    też hasło....
  10. }
  11. ?>


Funkcja haszująca MD5 gwarantuje, że treść wysłana w zapytaniu do bazy NIE będzie żadnym poleceniem. Jeżeli hasło istnieje (albo ktoś trafił na ciąg po haszowaniu dajacy jakiśtam rezultat, który jest w bazie), to sprawdzamy login z zapodanym wcześniej. Takie podejście od tyłu winksmiley.jpg Najczęściej wykorzystywane jest pole [login] do takich zabaw jak SQL Injection. A w tym przypadku nie ma na to szans.

Proszę o ocenę pod względem bezpieczeństwa...

PS> Hasła w bazie są oczywiście shaszowane aarambo.gif
PS2> w zmiennej $sql nie ma żadnych Backslashy (czyli [\])
MatheW
Super - sprawdzasz tylko po haśle - więc zakladasz ze kazdy user MUSI miec inne haslo - zle - wybierz po loginie (ktory winien byc unikalny) i potem czy hash hasła = shaszowane wczesniej haslo z bazy.
Rzast
@MatheW: Właśnie chodziło mi o to, żeby nie dopuścić do bazy danych zawartości $_POST['login']. Bezpieczne jest zhaszowane hasło

Racja, nie wpisałem ostatniej modyfikacji....
  1. <?php
  2. $sql='SELECT id,login FROM baza WHERE haslo="'.md5($_POST['haslo']).'"';
  3. $wynik=mysql_query($sql);
  4. if (mysql_num_rows($wynik)>=1){
  5. $ok=true;
  6. while (($dana=mysql_fetch_row($wynik))&&($ok==true)){
  7. if ($dana[1]==$_POST['login'])){
  8. //Zalogowany
  9. $ok=false;
  10. $_Session['id']=$wynik[0];
  11. //Dalsze czynności....
  12. }
  13. }
  14. }else{
  15. //złe hasło
  16. }
  17. ?>

Hasła mogą być takie same, ale różne loginy (sprawdzane przy rejestracji) jednoznacznie wskazują na dane konto. Rkingsmiley.png
MatheW
Cytat
@MatheW: Właśnie chodziło mi o to, żeby nie dopuścić do bazy danych zawartości $_POST['login']. Bezpieczne jest zhaszowane hasłoRacja, nie wpisałem ostatniej modyfikacji....
To co zrobiłeś jest beznadziejne - pobierasz z bazy uzytkowników którzy mają takie same hasła! A takie same hasła moze miec paru userow. Wiec wynik moze zwrocic ich kilku - skad wiesz ktory to. W Twoim przpadku addslashes zupełnie wystarczy. Oczywiście przy rejestracji najlepiej zabron pewnych znakow w loginie, zeby nie sprawial trudnosci - najlepiej zostawic znaki alfanumeryczne, podkreslenia i spacje
Rzast
MatheW: Przyjżałeś się? Ale tak naprawdę uważnie?
Piszesz:
Cytat
To co zrobiłeś jest beznadziejne - pobierasz z bazy uzytkowników którzy mają takie same hasła! A takie same hasła moze miec paru userow. Wiec wynik moze zwrocic ich kilku - skad wiesz ktory to.

a w kodzie jest:
  1. <?php
  2. if (mysql_num_rows($wynik)>=1){//jeżeli jest jakiś user (userzy) o takim haśle...
  3. $ok=true; //ustaw zmienną pomocniczą 
  4. while (($dana=mysql_fetch_row($wynik))&&($ok==true)){// dekoduj wynik z bazy dopóki pomocnicza prawdziwa
  5. if ($dana[1]==$_POST['login'])){ //jeżeli jest taki login to...
  6. //Zalogowany
  7. $ok=false; //skasuj pomocniczą
  8. $_Session['id']=$wynik[0]; //ustaw sesję
  9.  ...itd
  10. ?>

Czy wytłumaczyć dokładniej?
pozdrawiam
eai
To jest bez sensu... a jeśli w bazie masz założymu 1 000 000 userów gdzie 10 000 na takie same hasło... Wtedy zalogowanie jednocześnie 1 000 userów, obciąży serwer. Po co tak robić?

Lepiej zrobić tak:
Login: [A-Za-Z0-9_-]
Hasło: tu już dowolnie i tak hasło trzymamy w bazie jako md5, wiec dodanie jakichkolwiek znaków ' " które mogłby by spowodować zmiane zapytania nic tu nie dadzą.

Po co sobie utrudniać życie i kombinować?
paziek
Witam,

Czytam wątek już drugi raz (pierwszy raz ok. 3 miesiące temu, kiedy php to było dla mnie jeszcze nowość) i dalej nie jestem pewien co do sposobu zabezpieczenia.


Do tej pory używałem ctype_digit() do liczb, oraz htmlspecialchars() do reszty.
Ogólnie to wolałbym używać zamiast htmlspecialchars() funkcję addslashes(), ale kilka postów zamieszczonym na tym forum skutecznie zniechęciło mnie do niej. A mianowicie teksty typu: "A ja podwójnie robię addslashes", jakieś wyrażenia regularne, cuda nie widy..

Czy istnieje możliwość na 'obejście' addslashes()? Tzn przekazać do zmiennej nie wyeskejpowany cudzysłów (podwójny czy pojedyńczy) ?


ps. addslashes() dlatego, że zauważyłem iż MySQL wykonuje swego rodzaju stripslashes() na przychodzących danych, więc oszczędza to miejsce i nie trzeba dekodować później danych z wartości html'owych.


I o co chodzi z tym poruszeniem na temat UNION?
Przeczytałem artykuł http://www.really-fine.com/SQL_union.html i mniej więcej wiem na czym to polega..
Jeśli wyeskejpuje zmiennę lub sprawdze czy są liczbowe, to powinienem być bezpieczny przed tym, racja?



Nie potrzebuję alternatyw do wspomnianych funkcji (czytać manuala potrafię tongue.gif ) , jedynie potwierdzenie od kogoś doświadczonego, czy addslashes() to 100% zabezpieczenie przed cudzysłowiami (nie SQL Injection).
Oczywiście, post Nospora polecający używanie addslashes() przy zmiennych tekstowych daje mi 99% pewności, iż to tylko moja paranoja, ale ten 1% to o 1% za dużo niepewności smile.gif


Swoją drogą, czy składnia typu
  1. <?php
  2. "SELECT * FROM table WHERE cos = '".$_POST."'";
  3. ?>

[bez tych slashy..]
ma jakieś walory pod względem bezpieczeństwa? Używam ".$zmienna." tylko dlatego, że edytor mi wtedy ładnie koloruje taką składnie, ale kto wie, może to coś daje 'gratis'? Wydajność? Bezpieczeństwo?



Dzięki z góry za pomoc w tej sprawie,
Paziek.
Jarod
Cytat(paziek @ 29.03.2007, 19:20:36 ) *
Czy istnieje możliwość na 'obejście' addslashes()? Tzn przekazać do zmiennej nie wyeskejpowany cudzysłów (podwójny czy pojedyńczy) ?

http://pl.php.net/manual/pl/function.mysql-escape-string.php
paziek
Jarod: Dzięki ale nie dzięki ;o

Po pierwsze, cytujesz fragment postu i odpowiadasz na ten fragment (nawet jak by go wyjąć z kontekstu) czymś zupełnie innym :/ Zadatki na polityka tutaj widzę sadsmiley02.gif

Po drugie, tak jak napisałem, nie potrzebuje alternatywy do wspomnianych funkcji, ani gotowego rozwiązania na SQL Injection, koduje swoje aplikacje 'w miarę potrzeb' i potrafię posługiwać się manualem oraz goglami.
Przeczytałem już tyle artykułów oraz postów na forum, że wiem wystarczająco dużo na ten temat.



Chciałem się tylko dowiedzieć, czy istnieje jakiś bug, dziura, sposób, cokolwiek w funkcji addslashes(), który umożliwiłby wprowadzenie do zmiennej nie wyeskejpowanego cudzysłowia, bo nieco zwątpiłem w tą funkcję, zapewne nadinterpretacją kilku postów. To (prawie) wszystko.


Jakiś .. chakier się wypowie? snitch.gif
akubiczek
Tak, istnieje taki bug. Nazywa się on:

$slashedVar=str_replace('\"','"',addslashes($sourceVar));

Tylko to programista musiałby go popełnić.. smile.gif Moim zdaniem, masz faktycznie paranoję tongue.gif


I na koniec: Jarod dobrze ci napisał - do escepowania zmiennych, które umieszczasz w zapytaniu SQL służy mysql_real_escape_string().

I na drugi koniec: ani addslashes() ani htmlspecialchars() nie służą do tego, do czego próbujesz je użyć (patrz punkt wyżej). htmlspecialchars() stosujesz w momencie wyświetlania treści na stronie, aby zabezpieczyć się przed złośliwym działaniem właśnie na poziomie przeglądarki (HTMLa) a nie bazy.
L00zak
php5, pdo i podpinanie, a skończą się wam problemy z addslashes(), mysql_real_escape_string() i magic_quotes tongue.gif
.radex
Czy ktoś, kto się na tym zna może mi odpowiedzieć:

Jest tu wiele sprzecznych wypowiedzi

I czy "mysql_escape_string" w całkowicie wyklucza możliwość przeprowadzenia ataku SQL Injection, czy konieczne są jakieś modyfikacje zapytań (jak w pierwszym poście)? I proponuję administracji posprzątać temat, bo po przeczytaniu nic mi się kupy nie trzyma:P
Jarod
Stosuję mysql_escape_string + filtrowanie danych i moim zdaniem jest to w zupełności bezpieczne.

A przy okazji jak filtrować na poziomie postgresql'a?

EDIT: @radex_p - bo nie znalazłem odpowiednika dla postgresql'a
.radex
skoro mysql_escape_string (nie licząc standardowych procedur filtrujących) jest good, to czemu nie użyć podobnej funkcji przeznaczonej dla postgre'a, lub PHP'owskiej wbudowanej?
sobstel
są sytuacje kiedy da się ją obejśc, nie jest tajemnicą że najlepiej stosować tzw. prepared statements. więcej: http://ilia.ws/archives/103-mysql_real_esc...Statements.html
starach
Witam.
Przeczytałem ten temat dwa razy. Dwa razy dostałem oczopląsu i palpitacji serca.
Temat niby jeden, ale skaczecie od wątku do wątku. Oszaleć można.
Postaram się w skrócie podsumować poprzednie wypowiedzi, zanim przejdę do swojego pytania,
jako że poprzednie podsumowania ułatwiły mi czytanie tego wątku.

1. Należy sprawdzać czy liczba jest liczbą, to znaczy że jeśli przesyłamy urlem id rekordu z tabeli musimy sprawdzić czy jest on liczbą.
2. Dodawanie ukośników przez addslashes() lub mysql_real_escape_string() w zmiennych typu string.
(Z tekstu tutaj wyczytałem że mysql_real_escape_string() robi to lepiej. Czy tak jest i dlaczego ?)
3. Ostatnim problemem z SQL-Injection jakiego zdołałem się tutaj doczytać jest słowo kluczowe SQL 'UNION'
dzięki któremu można pobrać więcej danych.

W mojej opinii nie należy trząść portkami przed UNION jeśli zamiast gwiazdki po SELECT wypisuje się nazwy pól które chce się pobrać z tabeli. Jeśli się mylę poprawcie mnie.

Moje pytanie(oprócz tego w punkcie drugim):
Chciałbym się dowiedzieć jak mam usunąć ze zmiennej wszystkie spacje nie tylko te z przodu i z tyłu - trim()
Mam z tym problem bo spacje można zapisać jeszcze w inny sposób niż ' ' a ja niestety na tych metodach zapisu się nie znam.

Poniżej przedstawiłem swoją metodę dodającą do łańcucha znaków wsteczne ukośniki.
Prosiłbym o jakieś komentarze czy jest ona bezpieczna i czy zamiast addslashes powinienem zastosować mysql_real_escape_string()
  1. <?php
  2. public function sanitize($input, $force=false)
  3. {
  4. if(!get_magic_quotes_gpc() || $force == true)
  5. {
  6. if(is_array($input))
  7. {
  8. foreach($input as $key => $val)
  9. {
  10. $input[$key] = addslashes($val);
  11. }
  12. return $input;
  13. } else {
  14. return addslashes($input);
  15. }
  16. } else {
  17. return $input;
  18. }
  19. }
  20. ?>

Dziękuję za przeczytanie i odpowiedź na te moje wypociny winksmiley.jpg
Kicok
Cytat
Prosiłbym o jakieś komentarze czy jest ona bezpieczna

To zależy gdzie się jej użyje:
  1. <?php
  2.  
  3. // 1, zabezpieczone przed SQL injection
  4. $_GET['name'] = $this->sanitize( $_GET['name'] );
  5. mysql_query( "SELECT * FROM some_table WHERE name = '{$_GET['name']}'" );
  6.  
  7.  
  8. // 2, niezabezpieczone przed SQL injection
  9. $_GET['sort'] = $this->sanitize( $_GET['sort'] );
  10. mysql_query( "SELECT * FROM some_table ORDER BY {$_GET['sort']}" );
  11.  
  12. ?>



A co do usuwania spacji to nie rozumiem problemu. Chodzi ci o to, że chcesz usunąć: ' ', '&nbsp;', '%20', itp? Tylko po co, skoro 2 i 3 przykład sam z siebie w spację się nie zamieni...
No ale zawsze możesz użyć str_replace" title="Zobacz w manualu PHP" target="_manual
starach
Czyli nie ma się co zastanawiać tylko walnąć str_replace na ' '.
Ok dzięki.

Co do mysql_real_escape_string() to poniżej jest cytat z postu http://forum.php.pl/index.php?s=&showt...st&p=172835 calls MySQL's library function mysql_escape_string, which prepends backslashes to the following characters: NULL, \x00, \n, \r, \, ', " and \x1a.

addslashes() : Returns a string with backslashes before characters that need to be quoted in database queries etc. These characters are single quote ('), double quote ("), backslash (\) and NUL (the NULL byte).
SirZooro
Cytat(orglee @ 12.05.2007, 17:08:15 ) *
Witam.
Przeczytałem ten temat dwa razy. Dwa razy dostałem oczopląsu i palpitacji serca.
Temat niby jeden, ale skaczecie od wątku do wątku. Oszaleć można.
Postaram się w skrócie podsumować poprzednie wypowiedzi, zanim przejdę do swojego pytania,
jako że poprzednie podsumowania ułatwiły mi czytanie tego wątku.

Też mam (niestety) podobne odczucia...

Cytat(orglee @ 12.05.2007, 17:08:15 ) *
1. Należy sprawdzać czy liczba jest liczbą, to znaczy że jeśli przesyłamy urlem id rekordu z tabeli musimy sprawdzić czy jest on liczbą.

Tak. Warto użyć do tego wyrażenia regularnego takiego jak to:
Kod
^[1-9][0-9]{0,8}$

Powyższe wyrażenie sprawdza jeszcze ilość cyfr - raczej mało kto będzie miał ponad miliard rekordów smile.gif

Cytat(orglee @ 12.05.2007, 17:08:15 ) *
2. Dodawanie ukośników przez addslashes() lub mysql_real_escape_string() w zmiennych typu string.
(Z tekstu tutaj wyczytałem że mysql_real_escape_string() robi to lepiej. Czy tak jest i dlaczego ?)

mysql_real_escape_string() uwzględnia zestaw znaków używany podczas łączenia się z bazą danych, więc będzie też poprawnie działać jeżeli używasz np. Unicode.

Co do ukośników - z tego co się orientuję, to kilka lat temu MySQL był wyjątkiem i ich wymagał, a inne bazy danych z którymi miałem do czynienia (PostgreSQL, MS SQL, Oracle) akceptowały podwójny apostrof (dwa apostrofy obok siebie). Obecnie także MySQL je akceptuję. Ja tutaj zalecam używanie mysql_escape_string() (dla MySQL) i pg_escape_string() (dla PostgreSQL), ew. podobnych funkcji (jest to opisane w dokumentacji PHP).

Przed wywołaniem tych funkcji warto także sprawdzić czy string wpisany do formularza nie jest za długi, i go obciąć. Warto także wywołać trim() - raczej nie ma sensu przechowywać dodatkowych spacji, które i tak nie będą wyświetlone.
Cytat(orglee @ 12.05.2007, 17:08:15 ) *
3. Ostatnim problemem z SQL-Injection jakiego zdołałem się tutaj doczytać jest słowo kluczowe SQL 'UNION'
dzięki któremu można pobrać więcej danych.

W mojej opinii nie należy trząść portkami przed UNION jeśli zamiast gwiazdki po SELECT wypisuje się nazwy pól które chce się pobrać z tabeli. Jeśli się mylę poprawcie mnie.

Przy UNION jest tylko ważne aby zgadzała się ilość kolumn i ich typy były zgodne, dlatego "SELECT *" przed niczym nie chroni. Dlatego np. takie zapytanie zadziała:
Kod
SELECT * FROM produkty WHERE id=0 UNION SELECT login, haslo, 0, 0, 0 FROM uzytkownicy


Cytat(orglee @ 12.05.2007, 17:08:15 ) *
Moje pytanie(oprócz tego w punkcie drugim):
Chciałbym się dowiedzieć jak mam usunąć ze zmiennej wszystkie spacje nie tylko te z przodu i z tyłu - trim()
Mam z tym problem bo spacje można zapisać jeszcze w inny sposób niż ' ' a ja niestety na tych metodach zapisu się nie znam.

Użyj czegoś takiego:
Kod
echo preg_replace('/\s+/', ' ', ' a   b   c  ');

To polecenie zamienia kilka spacji (i innych "białych" znaków) na jedną spację. Nie usuwa ono jednak całkowicie spacji z początku i końca - trzeba albo to wyrażenie poprawić, albo dodatkowo użyć trim(). Jeżeli chcesz natomiast wyciąć wszystkie spacje, usuń spację z drugiego parametru.

Ktoś wcześniej wspomniał też o mod_rewrite i .htaccess - można tego użyć jako dodatkowego mechanizmu zabezpieczeń, trzeba tylko pilnować aby nigdzie na stronach nie pojawił się rzeczywisty adres stron w serwisie. Poza tym warto także pamiętać że zawsze można próbować zgadnąć nazwy stron i nazwy parametrów.

Poza tym jest jeszcze kwestia znaku komentarza "--" w SQL, i tzw. ataki wielofazowe, ale o tym nie chce mi się drugi raz pisać - zerknijcie sobie tutaj: Ataki SQL Injection smile.gif
bełdzio
tylko po co te regexpy?
starach
Cytat(bełdzio @ 15.06.2007, 17:54:59 ) *
tylko po co te regexpy?
Właśnie po co skoro istnieje filter_ input()" title="Zobacz w manualu PHP" target="_manual
Nightmare
Po to żeby ci z php4 też mieli bezpieczne formularze winksmiley.jpg
bełdzio
Cytat(SirZooro @ 14.06.2007, 19:18:29 ) *
Kod
^[1-9][0-9]{0,8}$


Kod
echo preg_replace('/\s+/', ' ', ' a   b   c  ');


1. ctype_digit
2. str_replace

?
Sedziwoj
z ctype_digit() trzeba ostrożnie, bo jeśli nie dostanie stringa tylko int np. 34 to zwróci false, do tego jeśli string jest puszty "" to zwraca true.
dlatego jak ktoś chce użyć do sprawdzania danch np. z GET to powinien użyć takiego złożenia
  1. <?php
  2. if ( !empty($_GET['id']) && ctype_digit($_GET['id']) ){
  3.  //dobre id (string składa się z samych liczb)
  4. }else{
  5.  //Zły, pusty/zawiera inne znaki
  6. }
  7. ?>
Black-Berry
Postanowiłem przyłączyć się do dyskusji. Kiepski ze mnie teoretyk więc od razu podam moj sposób rozuminienia tego o czym piszecie...
  1. <?php
  2. //clasa t_panel
  3. class t_panel
  4. {
  5. var $item_id; //pole trzymajace numer wiersza tabeli
  6. var $user_name; //pole trzymajacy nazwe pobraną z tabeli mysql
  7.  
  8. function t_panel() //konstruktor klasy
  9. {
  10. $this->item_id = $_GET["item_id"]; //pobieranie numeru przekazanego za pomocą _get
  11. if (!is_int($this->item_id) $this->item_id = 0; //ustawianie na 0 jesli nie jest liczba całk.
  12. $this->load_data_from_database();
  13. }
  14.  
  15. function load_data_from_database()
  16. {
  17. $query ="SELECT * FROM moja_tabela WHERE id=".$this->item_id." LIMIT 1";
  18. $result = mysql_query ( $query ) or die ( _MYSQL_ERROR_.":".mysql_error());
  19. $row = mysql_fetch_array($result, MYSQL_ASSOC);
  20. $this->user_name = $row["nazwa_uzytkownika"];
  21. }
  22.  
  23. function drop()
  24. {
  25. echo $this->user_name;
  26. }
  27. }
  28. ?>
Czy ktoś będzie się mógł mi włamać przy takim kodzie?
Sedziwoj
Nie, zawsze będzie 0, ponieważ tu jest błąd:
  1. <?php
  2. $this->item_id = $_GET["item_id"]; //pobieranie numeru przekazanego za pomocą _get
  3. if (!is_int($this->item_id) $this->item_id = 0;
  4. ?>

Zmienne z tablicy $_GET są zawsze typu string, więc musisz najpierw rzutować na int, bo:
Cytat
Returns TRUE if var is an integer, FALSE otherwise
Black-Berry
Tyle się rozpisaliście na tym wątku, a jak ktoś (chyba słusznie) zauważył nie da sie praktycznie włamać do bazy MYSQL za pomocją SQL injection jeśli zmienne przekazywane metodą _GET są tylko i wyłącznie liczbami (a jak sądzę tak jest w większości przypadków.klk

Myślę też, że jeśli w przypadku przekazywania stringów zastosujemy funkcję real_escape_string() to włamanie SQLInjection będzie niemożliwe. Jeśli się myslę to prosze mnie skorygować bo w tym wątku czas na wniski.

Pozdrawiam.
bełdzio
  1. SELECT * FROM tabelka WHERE id = $_GET['id'];


-> $_GET['id'] = 5 or 1=1

wynik =
  1. SELECT * FROM tabelka WHERE id = 5 OR 1=1


efekt: pobranie wszystkich wpisów
Black-Berry
dry.gif że też ja na to nie wpadłem.... worriedsmiley.gif

Sory, że dalej drążę temat ale nie chcę się obudzic z ręką w nocniku później...
Czy takie funkcje mnie ochronią przed SQL Injection? Czy powinienem do nich coś jeszcze dodać ?

  1. <?php
  2. function mysql_valid_number( $a_value )
  3. {
  4. if ( !empty( $a_value ) && ctype_digit( $a_value ) ){
  5. return $a_value;
  6. }else{
  7. return 0;
  8. }
  9. }
  10.  
  11. function mysql_valid_string( $a_value )
  12. {
  13. return mysql_real_escape_string( $a_value );
  14. }
  15.  
  16. $id = mysql_valid_number( $_GET["id"] );
  17. $name = mysql_valid_string( $_GET["name"] );
  18. $query_1 = "SELECT * FROM mytable WHERE id = ".$id."";
  19. $query_2 = "SELECT * FROM mytable WHERE name = ".$name."";
  20. ?>

EDIT: poprawiony return dla mysql_valid_string;
bełdzio
w mysql_valid_string return by się przydał
LEW21
Black-Berry, po co tak kombinować? Po prostu do intów zawsze używaj (int) a do stringów mysql_real_escape_string albo PDO i bindParamy
Sedziwoj
Cytat(LEW21 @ 24.07.2007, 15:30:47 ) *
Black-Berry, po co tak kombinować? Po prostu do intów zawsze używaj (int) a do stringów mysql_real_escape_string albo PDO i bindParamy

A wiesz co uzyskasz po takim czymś:
  1. <?php
  2. $strIn = '-2';
  3. $intT = (int)$strIn;
  4. var_dump($intT);
  5. if( ctype_digit($strIn) ){
  6.  echo "Tylko cyfry";
  7. }else{
  8.  echo "Nie tylko cyfry";
  9. }
  10. ?>


A trzeba pilnować, ja coś ma być liczbą dodatnią niech nią będzie, bo potem gdzieś ktoś nie przewidzi, że może być ujemną i się posypie, a czasem jest tak że nie wywala błędu i trzeba szukać.
Aby jakiś algorytm działał poprawnie, muszą być spełnione wszystkie warunki początkowe.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.