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
Najki
Pytania o streszczenie wątku, posty z "genialnymi" skryptami nadającymi się tylko na przedszkole i inne tego typu, będą bez ostrzeżenia usuwane przez moderatorów.
To mówiłem ja, Jarząbek... znaczy nospor dnia 2007-12-10
-------------------------------------------------------------------------------


SQL Injection (zwane też "SQL Insertion") to (rzekomo) najprostszy sposób włamu na stronę. Spowodowany jest on niepełnym sformułowaniem zapytań do MySQL.

Przykład. Dajemy na stronie możliwość edycji profilu. Zapytanie do SQL wygląda następująco:
  1. <?php
  2. $query = &#092;"update uzytkownicy set pole='$dane' where id='$id'\";
  3. ?>

Osoba włamująca się na stronę umieszcza całkiem prosty, odpowiedni ciąg znaków/poleceń w dowolnym polu edycji tego profilu, który wygląda np. tak (dla zmiany hasła użytkownika o dowolnie wybranym, przez atakującego numerze ID):
  1. <?php
  2. ', haslo='nowe_haslo' WHERE id = '1
  3. ?>


W taki oto prosty sposób, osoba atakująca zmieniła hasło użytkownikowi o ID=1 (zazwyczaj administrator). W podobny sposób można również wyciągnąć dowolne dane z tabeli SQL.

W każdym razie. Poszperałem, pomyślałem i zebrałem wszystko do kupy. Zamieszczam to tutaj razem, oraz proszę o rozbudowanie tego topica, gdyż nie znalazłem na tym forum więcej informacji o "SQL Injection".

Oto co możemy dokonać:
1. Możemy sformułować nasze zapytanie do SQL tak:
  1. <?php
  2. $query = 'update `uzytkownicy` set `pole`=\"'.$dane.'\" where `id`=\"'.$id.'\";';
  3. ?>

2. Przy wstawianiu numerów ID do zapytań należy stosować tzw. rzutowanie typów:
  1. <?php
  2. $id = (int)$_GET['id'];
  3. // lub
  4. $id = intval($_GET['id']);
  5. ?>

3. Przy wstawianiu tekstów, należy wyciąć niebezpieczne znaki przy pomocy funkcji:
  1. <?php
  2. $string = mysql_real_escape_string($_POST['string']); // PHP5
  3.  
  4. $string = mysql_escape_string($_POST['string']); /* lub */ $string = addslashes($_POST['string']); // PHP4
  5. ?>


Może nie ma tego dużo, ale jest to już jakaś podstawa do zabezpieczenia strony/skryptu przed prostym i niezwykle niebezpiecznym, SQL Injection. Proszę osoby obeznane w tym temacie, aby dopisały tu własne propozycje metod zabezpieczenia się przed tym atakiem.
Vengeance
Cytat(Najki @ 2004-11-25 00:13:57)
Oto co możemy dokonać:
1. Możemy sformułować nasze zapytanie do SQL tak:
  1. <?php
  2. $query = 'update `uzytkownicy` set `pole`=\"'.$dane.'\" where `id`=\"'.$id.'\";';
  3. ?>

2. Numer ID warto ustawiać w sposób $_GET['id'], lub $_POST['id'], można też ustawić go w nast. sposób:
  1. <?php
  2. $id = (int)$_GET['id'];
  3. ?>


Może nie ma tego dużo, ale jest to już jakaś podstawa do zabezpieczenia strony/skryptu przed prostym i niezwykle niebezpiecznym, SQL Injection. Proszę osoby obeznane w tym temacie, aby dopisały tu własne propozycje metod zabezpieczenia się przed tym atakiem.

punkt 1. twojego "zabezpieczenia" nie ma nic do rzeczy z rzeczywistym bezpieczeństwem przynajmniej wg mnie

punkt 2. ja stosuje po prostu addslashes() i filtruje dane z POST GET COOKIE itd. tzn jak ma byc liczba do liczba a nie string smile.gif

stosujac gotowe skrypty ala phpbb itd. dopisuje zawsze w jakims glownym pliku
usuwanie s url-a wystapien wyrazow "<script>" i "UNION" co zabezpiecza przez script kiddie
ActivePlayer
Z tego co wiem to mysql nie wykonuje zapytan typu "zapyta1;zapyt2" od sstrony php wiec tego nei masz sie co bac... co do filtrowania danych...

mysql_escape_string" title="Zobacz w manualu PHP" target="_manual
Najki
Cytat(Vengeance @ 2004-11-25 00:34:40)
punkt 1. twojego "zabezpieczenia" nie ma nic do rzeczy z rzeczywistym bezpieczeństwem przynajmniej wg mnie

Gdzieś znalazłem informację, że niby jednak to ma pomóc (głównie chodzi o średnik tam też o średnik na końcu zapytania)
Cytat(Vengeance @ 2004-11-25 00:34:40)
punkt 2. ja stosuje po prostu addslashes() i filtruje dane z POST GET COOKIE itd. tzn jak ma byc liczba do liczba a nie string

Czy czasem $_POST, $_GET i $_COOKIE nie mają automatycznie dodawanych slash'y ?
Cytat(Vengeance @ 2004-11-25 00:34:40)
stosujac gotowe skrypty ala phpbb itd. dopisuje zawsze w jakims glownym pliku
usuwanie s url-a wystapien wyrazow "<script>" i "UNION" co zabezpiecza przez script kiddie

Tak będzie OK? (nie znam się na wyrażeniach regularnych, a chciałbym, aby w tym topicu wszystko było jasno opisane, co by nikt problemów nie miał)
  1. <?php
  2. preg_replace( '%<script>%', '', $zmienna );
  3. ?>
Kinool
zabezpieczenie w stylu:
  1. <?php
  2. $query = 'update `uzytkownicy` set `pole`=\"'.$dane.'\" where `id`=\"'.$id.'\";';
  3. ?>
to jak juz powiedziano zadne zabezpieczenie a pozatym zmnijsza wydajnosc zapytania, umieszczanie wartosci liczbowych w momiedzy " " powiduje iz MySQL mysli ze ma do czynienia ze znakami (stringami) i niepotzrebnie musi konwertowac typy.

Przylacze sie do tego co juz powiedziano, uzywac Zmiennych globalnych, i filtrowac wszystko, to co ma byc liczba to konwertowac na liczbe np:
  1. <?php
  2. $_GET['id'] = intval($_GET['id']);
  3. ?>
a to co ma byc stringiem dodawac slashe (addslashes).

Podstawowa zasada to nie ufac nikomu i spodziewac sie najgorszego!
budowac aplikacje tak by wytrzymaly wybuch nuklearny smile.gif

w jednym ze swoich projektw zrobilem petle na foreach ktora z kazdego elemenu tablicy ($_GET, $_POST, $_COOKIE) zamieniala ewentualn wystapienia wyrazen takich jak "SELECT, UPDATE, INSERT, DELETE, WHERE AND" dodajac do nich np twarda spacje &nbsp; lub jakis inny znak co powodowalo ze ew. zapytanie bylo by z gory obarczone bledem.

coprawda rozwiazanie takie nie jest eleganckie bo wszystkie wystapienia tych wyrazeni byly zamieniane nawet jesli ktos nie mial zlych intencji ale sa one bardzo zadko uzywane w naszym slownictwie a dodanie np. twardej spacji praktycznie niczego nie zmienia w wygladzie takiego komentarza, posta etc.
johnson
Cytat(Kinool @ 2004-11-25 07:48:38)
to co ma byc stringiem dodawac slashe (addslashes)

nie rozumiem dlaczego wszyscy piszą o addslashes, przecież php automatycznie dodaje slashe do wszystkich zmiennych $_GET i $_POST i włamanie opisane przez Najki
  1. <?php
  2. ', haslo='nowe_haslo' WHERE id = '1

nie ma prawa zadziałać.

Czy mógłby ktoś wyjaśnić mi tą sytuację?
Najki
Owszem dodaje, ale chyba tylko, gdy na serwerze jest włączone magic_quotes_gpc ?
A jeśli nie to jakim prawem kolega mi się włamał? snitch.gif
morrison
Temat ciekawy, ale w zasadzie nie wiem jeszcze co moglbym zrobic w swojej aplikacji aby uniemozliwic taki atak i aby bylo to zrobione w profesjonalny sposob. Gdyby ktos mogl zerknac na kod i pomoc mi.
Oto kod ktory sluzy do sprawdzenia hasla i nazwy usera:
  1. <?php
  2.  
  3. // utworzenie krotkich nazw zmiennych i spr. czy dane sa przek. w zm. sesji
  4. if (!isset($_SESSION['nazwa_uz']))
  5. $_SESSION['nazwa_uz'] = $HTTP_POST_VARS['nazwa_uz'];
  6. if (!isset($_SESSION['haslo']))
  7. $_SESSION['haslo'] = $HTTP_POST_VARS['haslo'];
  8.  
  9. //spr. czy zostalo nadane nowe haslo
  10. if (isset($_SESSION['nowe_haslo']))
  11. $_SESSION['haslo'] = $_SESSION['nowe_haslo'];
  12.  
  13. if (($_SESSION['nazwa_uz'] && $_SESSION['haslo']) || ($_SESSION['nazwa_uz'] == '' || $_SESSION['haslo'] == ''))
  14. // proba logowania, sprawdzenie czy podano login oraz haslo
  15. {
  16. if (loguj($_SESSION['nazwa_uz'], $_SESSION['haslo']))
  17. {
  18. // jesli uzytkownik znajduje sie w bazie danych rejestracja identyfikatora
  19. $HTTP_SESSION_VARS['prawid_uzyt'] = $_SESSION['nazwa_uz'];
  20.  
  21.  
  22. }
  23. else
  24.  
  25. ?>


a to kod funkcji wykonujacej to sprawdzenie:
  1. <?php
  2.  
  3. function loguj($nazwa_uz, $haslo)
  4. // sprawdzenie nazwy uzytkownika i hasla w bazie danych
  5. // jezeli sie �zgadza, zwraca true
  6. // jezeli nie, zwraca false
  7. {
  8. // polaczenie z baza danych
  9. $lacz = lacz_bd();
  10. if (!$lacz)
  11. return false;
  12.  
  13. // sprawdzenie unikatowosci nazwy uzytkownika
  14. $wynik = mysql_query(&#092;"select * from uzytkownik 
  15.  where nazwa_uz='$nazwa_uz'
  16.  and haslo = password('$haslo')&#092;");
  17. if (!$wynik)
  18.  return false;
  19.  
  20. if (mysql_num_rows($wynik) > 0)
  21.  return true;
  22. else 
  23.  return false;
  24. }
  25.  
  26. ?>

Chcialbym uniknac mozliwosci wlamania, poprzez wpisanie kodu SQL do pola haslo i uzytkownik:)
ActivePlayer
przyklad:
  1. <?php
  2.  
  3. $sql = mysql_query(&#092;"SELECT * FROM news WHERE id=\".$_GET['id']);
  4.  
  5. ?>


wywołanie normalne:
Kod
news.php?id=1
news.php?id=25
itd


wywołanie zmodyfikowane przez kogostam
np.
Kod
news.php?id=1;DROP%20TABLE%20news;


zabezpieczenie? ja znalazlem pare...

1. dodanie id2

  1. <?php
  2.  
  3. if(md5($_GET['id']*4)!=$_GET['id2'])die('Błędny url');
  4.  
  5. ?>


2. wymuszenie typu

  1. <?php
  2.  
  3. $id = (int)$_GET['id'];
  4.  
  5. ?>


3. mysql_escape_string

  1. <?php
  2.  
  3. $id = mysql_escape_string($_GET['id']);
  4.  
  5. ?>


ale mam wrazenie ze to dalej nie o to biega... z tych 3 które przedstawilem to pierwsze wydaje mi sie być najrozsądniejsze...
sobstel
Cytat(ActivePlayer @ 2005-02-26 21:45:06)
ale mam wrazenie ze to dalej nie o to biega... z tych 3 które przedstawilem to pierwsze wydaje mi sie być najrozsądniejsze...

osobiscie uwazam ze dosc dobrym rozwiazaniem jest odpowiednie zarządzanie uprawnieniami, np. stworzyc konto dla www, gdzie moga byc tylko SELECT, INSERT, UPDATE, ewentualnei DELETE

druga sprawa, czy probowales w praktyce wykonac przedstawione przez ciebie polecenie? standardowo (nie jestem pewny czy da sie to przestawic tak zeby bylo inaczej) przez mysql_querynie wykonasz dwóch zapytań
Vengeance
przez mysql_query() nie. ale funckje postgreSQL już to dopuszczają :/
Dlatego userzy tego drugiego mają większy problem.

Co do zabezpieczenia, nie wiem czym się tak przejmujecie? ;]
Ja stosuje jedynie addslashes() oraz usuwam slowo 'UNION' ze zmiennych
Riklaunim
dość często jest WHERE coś = liczba gdzie coś jest polem auto_increment i ma wartości liczbowe.. wystarczy przed wykonaniem zapytania sprawdzić czy is_numeric parametr dla Where
MoD
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)
MStaniszczak
Cytat
Ja do liczb stosuje najczęściej ereg (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)


Hmmm.... wykonanie ereg zajmuje nieco czasu (jak to wyrażeń regularnych). Chyba jednak lepiej się nieco przyłożyć i pobawić kombinacją is_numeric(), is_integer(), intval() i warunkami. Chyba każdy wie jakiego mniej więcej zakresu się spodziewa? Jak nie chcesz liczb ujemnych to po porostu wycinasz je warunkiem i już…
Po co z armatą na muchy;-)

Pozdrawiam
Marcin Staniszczak
Vengeance
@MStaniszczak: podobnież "is_numeric(), is_integer(), intval()" nie są zawsze dobrym wyjściem. Gdzieś czytałem, iż Zend Engine działa tak, iż te funkcje sprawdzają tylko typ zmiennej. Może to doprowadzać do przekłamań, dlatego niektórzy właśnie stosują eregi (co w tamtym artykule także polecano).
MStaniszczak
@Vengeance:
Więc działa to tak:
is_numeric() - sprawdza czy cos co podałeś jako argument jest cyfrą. Dokładniej czy nie ważne czy cyfra jest stringiem ('123') czy cyfrą (123) czy cyfrą ułamkową (123.123). Jeśli jest cyfrą zwraca true;

is_integer() - zwraca true TYLKO wtedy gdy parametr:
a) jest cyfra
b) jest typu integer (czyli dla '123' nie zwróci true)
c) jest cyfrą CAŁKOWITĄ (czyli dla 123.123 nei zwróci true).
WSZYSTKIE te punkty muszą być spełnione jednocześnie

intval() - nic nie sprawdza... Zamienia parametr na integera (jesli zaczyna się od cyfry). Czyli:
  1. <?php
  2. $i = intval('123')
  3. ?>

powoduje przepisanie do $i wartości 123 typu INTEGER.
  1. <?php
  2. $i = intval('123 ala ma kota')
  3. ?>

działa podobnie - w $i otrzymujemy INTEGER-a o wartości 123.
Dodatkowo intval() ignoruje początkowe białe znaki i oczywiście poprawnie obsługuję znaki +/- przed cyfrą.
W przypadku niepoprawnego parametru podanego do intval:
  1. <?php
  2. $i = intval('ala ma kota');
  3. ?>

zwraca 0 (czyli w przykładzie $i otrzymuje wartość 0).

I NIE MA ODSTPSTW OD TYCH REGÓŁ.
Zamieszanie może powstać gdy się nie wie jak te funkcje działają (jest ich więcej - to tylko 3 z całej grupy). Ale to tak jak z operatorami...
Zobacz co da w wyniku:
  1. <?php
  2. $ret = '123 ala'+'123ma kota';
  3. echo $ret;
  4. ?>


Pozdrawiam
Marcin Staniszczak
Vengeance
@MStaniszczak: ja tam nie wiem smile.gif Mówie tylko co czytałem. Skoro ktoś to dostrzegł w kodzie Zend Engine (może go analizowałeś, ja nie) to miał jakieś powody by tak twierdzić smile.gif Może już to poprawili albo coś. Przytaczam tylko swoją "wiedzę" na ten temat, choc sam także używam is_integer() itp.
MStaniszczak
@Vengeance: Ano analizowałem Zend Engina dość dokładnie (jeszcze raz mnie to czeka).
Oto funkcja odpowiedzialna za is_numeric (która nie jest częścią Zend Engine-u):

Kod
PHP_FUNCTION(is_numeric)
{
    zval **arg;
    int result;

    if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg) == FAILURE) {
  WRONG_PARAM_COUNT;
    }

    switch (Z_TYPE_PP(arg)) {
  case IS_LONG:
  case IS_DOUBLE:
     RETURN_TRUE;
     break;

  case IS_STRING:
     result = is_numeric_string(Z_STRVAL_PP(arg), Z_STRLEN_PP(arg), NULL, NULL, 0);
     if (result == IS_LONG || result == IS_DOUBLE) {
    RETURN_TRUE;
     } else {
    RETURN_FALSE;
     }
     break;

  default:
     RETURN_FALSE;
     break;
    }
}


A to np. is_string:
Kod
PHP_FUNCTION(is_string)
{
    php_is_type(INTERNAL_FUNCTION_PARAM_PASSTHRU, IS_STRING);
}

do tego php_is_type:
Kod
static void php_is_type(INTERNAL_FUNCTION_PARAMETERS, int type)
{
    pval **arg;

    if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg) == FAILURE) {
  php_error_docref(NULL TSRMLS_CC, E_WARNING, "Only one argument expected");
  RETURN_FALSE;
    }

    if (Z_TYPE_PP(arg) == type) {
  if (type == IS_OBJECT) {
     zend_class_entry *ce;
     ce = Z_OBJCE_PP(arg);
     if (!strcmp(ce->name, INCOMPLETE_CLASS)) {
    RETURN_FALSE;
     }
  }
  if (type == IS_RESOURCE) {
     char *type_name;
     type_name = zend_rsrc_list_get_rsrc_type(Z_LVAL_PP(arg) TSRMLS_CC);
     if (!type_name) {
    RETURN_FALSE;
     }
  }
  RETURN_TRUE;
    } else {
  RETURN_FALSE;
    }
}


A is_integer, is_double, is_real ma jeszcze ładniejszą postać (sam sprawdź). To nie może działać źle - używaj bez obaw;-)

Pozdrawiam
Marcin Staniszczak
krzemian
W PHPBB też jest coś takiego używane, ale - znowu - nie prościej użyć rzutowania typów? Ostatnio zrobiłem coś takiego na zmiennej $id z GET'a i nawet jeśli dałem id=3fk5 to jeśli zrzutowałem to na (int) otrzymywałem 35. Chyba o to wam chodzi, nie?
Seth
To o czym piszesz sprawdza sie przy liczbach, natomiast do ciagow znakow trzeba juz inaczej do tego podchodzic.
MStaniszczak
@krzemian:
Cytat
Ostatnio zrobiłem coś takiego na zmiennej $id z GET'a i nawet jeśli dałem id=3fk5 to jeśli zrzutowałem to na (int) otrzymywałem 35. Chyba o to wam chodzi, nie?


Ciekawe co piszesz - sprawdź co zwróci skrypt...
  1. <?php
  2. $x = '3fk5';
  3. $a = (int)'3fk5';
  4. $b = (int)$x;
  5.  
  6. echo $a.'<br>'.$b;
  7. ?>


A teraz popróbuj:

  1. <?php
  2. $a = '1abc';
  3. $b = '2ii';
  4. $d = '-3ala ma kota a kot ma ale';
  5.  
  6. $ret = $a+$b;
  7. echo $ret.'<br>';
  8.  
  9. $ret += $d;
  10. echo $ret.'<br>';
  11.  
  12. $ret = $b*$d;
  13. echo $ret.'<br>';
  14.  
  15. ?>


Pozdrawiam
Marcin Staniszczak
ActivePlayer
Moze ktos napisze klase, lub zbiór funkcji, alby uniknąc tego typu problemów, tylko ze... tu problem nie polega na tym, co zrobic zeby sprawdzic jaki typ danych user wpisze, tylko raczej na tym jak mądrze napisac zapytanie.
MStaniszczak
Ja używam czegoś takiego (ma już swoje latka - dodałem tylko public;-):

  1. <?php
  2. require_once(ROOT_PATH.'Libraries/Tools/email.inc.php');
  3.  
  4. define('VALIDATE_EMAIL', 1);
  5. define('VALIDATE_STRING', 2);
  6. define('VALIDATE_INTEGER', 3);
  7. define('VALIDATE_DOUBLE', 4);
  8. define('VALIDATE_POSTCODE', 5);
  9. define('VALIDATE_BOOLEAN', 6);
  10.  
  11. class Validate {
  12. private function checkStrSize($value, $minSize, $maxSize) {
  13. if(strlen(trim($value))>$maxSize || strlen(trim($value))<$minSize)
  14. return false;
  15. else
  16. return true;
  17. }
  18.  
  19. //array( array('typ', 'value', 'min', 'max', 'correct')
  20. public function check($array) {
  21. $ret = array(true, $array);
  22.  
  23. $count = count($array);
  24. for($i=0; $i<$count; $i++) {
  25. switch($array[$i][0]) {
  26. case VALIDATE_EMAIL: // e-mail
  27. if(!tverifyEmail($array[$i][1])) {
  28. $ret[0] = false;
  29. $ret[1][$i][4] = false;
  30. } else
  31. $ret[1][$i][4] = true;
  32. break;
  33. case VALIDATE_STRING: // string
  34. if(!$this->checkStrSize($array[$i][1], $array[$i][2], $array[$i][3])) {
  35. $ret[0] = false;
  36. $ret[1][$i][4] = false;
  37. } else
  38. $ret[1][$i][4] = true;
  39. break;
  40. case VALIDATE_INTEGER: //integer
  41. if(!is_numeric($array[$i][1]) || 
  42. (strpos($array[$i][1], ',')!==false) || (strpos($array[$i][1], '.')!==false) ||
  43. $array[$i][1]<$array[$i][2] || $array[$i][1]>$array[$i][3]) {
  44. $ret[0] = false;
  45. $ret[1][$i][4] = false;
  46. } else
  47. $ret[1][$i][4] = true;
  48. break;
  49. case VALIDATE_DOUBLE: // double
  50. if(!is_numeric($array[$i][1]) || $array[$i][1]<$array[$i][2] || $array[$i][1]>$array[$i][3]) {
  51. $ret[0] = false;
  52. $ret[1][$i][4] = false;
  53. } else
  54. $ret[1][$i][4] = true;
  55. break;
  56. case VALIDATE_POSTCODE:
  57. if(!@ereg('^[0-9]{2}-[0-9]{3}$', $array[$i][1])) {
  58. $ret[0] = false;
  59. $ret[1][$i][4] = false;
  60. } else
  61. $ret[1][$i][4] = true;
  62. break;
  63. case VALIDATE_BOOLEAN:
  64. if(!is_bool($array[$i][1])) {
  65. $ret[0] = false;
  66. $ret[1][$i][4] = false;
  67. } else
  68. $ret[1][$i][4] = true;
  69. break;
  70. }
  71. }
  72.  
  73. return $ret;
  74. }
  75. }
  76. ?>


A plik email.inc.php:
  1. <?php
  2. if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN')
  3. $OS_detect = 'Windows NT';
  4. else
  5. $OS_detect = 'Unix';
  6.  
  7. function checkdnsrrWinNT($host, $type = '') {
  8. if(!empty($host)) {
  9.  
  10. if($type=='')
  11. $type = 'MX';
  12.  
  13. @exec(&#092;"nslookup -type=$type $host\", $output);
  14.  
  15. while(list($k, $line)=each($output)) {
  16. if(eregi( &#092;"^$host\", $line)) {
  17. return true;
  18. }
  19. }
  20. return false;
  21. }
  22. }
  23.  
  24.  
  25. function multiOScheckdnsrr($host, $type='') {
  26. global $OS_detect;
  27.  
  28. if(strcmp($OS_detect,'Windows NT')===0)
  29. return checkdnsrrWinNT($host, $type);
  30. else
  31. if(strcmp($OS_detect, 'Unix')===0) {
  32. if(strcmp($type, '')===|| strcmp($type, 'MX')===0)
  33. return checkdnsrr($host, MX);
  34. elseif(strcmp($type, 'A')===0)
  35. return checkdnsrr($host, A);
  36. elseif(strcmp($type, 'NS')===0)
  37. return checkdnsrr($host, NS);
  38. elseif(strcmp($type, 'SOA')===0)
  39. return checkdnsrr($host, SOA);
  40. elseif(strcmp($type, 'PTR')===0)
  41. return checkdnsrr($host, PTR);
  42. elseif(strcmp($type, 'CNAME')===0)
  43. return checkdnsrr($host, CNAME);
  44. elseif(strcmp($type, 'AAAA')===0)
  45. return checkdnsrr($host, AAAA);
  46. elseif(strcmp($type, 'ANY')===0)
  47. return checkdnsrr($host, ANY);
  48. }
  49. }
  50.  
  51. function verifyEmail($email) {
  52. $wholeexp = '/^(.+?)@(([a-z0-9.-]+?).[a-z]{2,5})$/i';
  53. $userexp = &#092;"/^[a-z0-9~!#$%&()-_+=[];:'\",./]+$/i\";
  54. if(preg_match($wholeexp, $email, $regs)) {
  55. $username = $regs[1];
  56. $host = $regs[2];
  57. if(multiOScheckdnsrr($host, 'MX')) {
  58. if(preg_match($userexp, $username)) {
  59. return true;
  60.  }else {
  61.  return false;
  62.  }
  63.  }else {
  64.  return false;
  65.  }
  66. }else {
  67. return false;
  68. }
  69. }
  70. ?>


Dalej validuje już w odpowiednich funkcjach - inaczej chyba ciężko;-)

Pozdrawiam
Marcin Staniszczak
docent
no to i moje 3 grosze. primo: nie ma to jak szczyt lenistwa:

Kod
foreach($_REQUEST as $key => $item) $$key = addslashes($item);


mam nadzieje, ze sie podoba tongue.gif oczywiscie nie wszedzie uzyteczne, niekoniecznie optymalne i nie zawsze dzialamy tylko na $_REQUEST. ale mniej wiecej juz znacie geneze smile.gif mozliwe modyfikacje oczywiscie:

Kod
foreach($_POST as $key => $item) $_POST[$key] = addslashes($item);


itd... smile.gif zamiast addslashes mozna dac intvalue, albo i obydwa.. jesli nie frunie duzo danych to i tak nie bedzie roznicy w czasie wykonywania skryptu - a nie trzeba z dokladnoscia ksiegowego sprawdzac czy o czyms (czyt. ktorejs zmiennej) nie zapomnielismy

pierwsza metoda (dla nei wiedzacych) symuluje niejako Register Globals na On, czyli zamiast odwolywac sie do strval($_REQUEST['zmienna']) mozemy po wykonaniu tamtego odwolac sie po prostu do $zmienna, ktora juz jest sparsowana pod kategm 'nieporzadanej' zawartosci

EDIT:

dziala oczywiscie i w druga strone. jesli do $rekord zczytamy sobie jakies dane z bazy danych to mozna sobie leniwie wrzucic:

Kod
foreach($rekord as $key => $item) $rekord[$key] = stripslashes($item);


tylko nalezy pamietac, aby czytac dane za pomcoa mysql_fetch_assoc lub row - nie mysql_fetch_array, gdyz wtedy mamy podwojne klucze w tablicy i wiadomo co sie stanie smile.gif
Vengeance
@docent: szczerze to zadna nowosc snitch.gif

----
Przez chwilke pomyslalem, ze mozna by zmienne przekazyawc przez:
www.site.com?int[postID]=4&string[mode]=showAll&bool[save]=true

I robic odpowiednie petle na tablicach, stosujac odpowiednie funkcje smile.gif
MStaniszczak
Cytat
Przez chwilke pomyslalem, ze mozna by zmienne przekazyawc przez:
www.site.com?int[postID]=4&string[mode]=showAll&bool[save]=true

I robic odpowiednie petle na tablicach, stosujac odpowiednie funkcje smile.gif


I otrzymali byśmy w GET coś takiego:-) Więc bardzo miło;-)

Kod
Array
(
    [int] => Array
        (
            [postID] => 4
        )

    [string] => Array
        (
            [mode] => showAll
        )

    [bool] => Array
        (
            [save] => true
        )

)


Pozdrawiam
Marcin Staniszczak
docent
Cytat(Vengeance @ 2005-03-04 20:04:20)
@docent: szczerze to zadna nowosc snitch.gif

----
Przez chwilke pomyslalem, ze mozna by zmienne przekazyawc przez:
www.site.com?int[postID]=4&string[mode]=showAll&bool[save]=true

I robic odpowiednie petle na tablicach, stosujac odpowiednie funkcje smile.gif

heihei ja nie mowie, ze nowowsc - ale informacja dla tych, ktorzy nie znaja smile.gif a istotnie - jest pomocna :] bardziej mnie interesowalo zdanie innych na ten temat - sposob w zasadzie sam sobie stwrozylem (choc pewnie kazdy na to wpadl we wlasnym zakresie) i interesowalo mnie tylko zdanie innych w tej kwestii smile.gif
tara
w sumei można też tak, np. dla newsów:
  1. <?php
  2.  
  3. if(isset($_GET['id'])) {
  4.   $query1 = &#092;"SELECT MAX(ID) FROM newsy\";
  5. list($d) = mysql_fetch_row(mysql_query ($query1));
  6.  
  7. if ($_GET['id']> $d) {
  8. print &#092;"Blad\";
  9. } else {
  10.  
  11. // kod 
  12.  
  13. }
  14. }
  15.  
  16. ?>


To blokuje wysiwetlanie newsa np. 9999 jak i tekstu. w zmiennej id.
limak
Cytat
To blokuje wysiwetlanie newsa np. 9999 jak i tekstu. w zmiennej id.
no dobra, ale to niewiele ma do zabiezpieczenia przed SQL Injection...
akurat wyswietlenie newsa nr 99999 nie wprowadza zadej nowej mozliwosci ataku....

wracając do tematu....

http://www.phpsolmag.org/pl/modules/wmpdow...php?cid=1&lid=6

tutaj jest darmowy artykuł z magazynu php solutions
tara
heh no ale jak ktoś wprawdzi DROP TABLE itp. to też zablokuje winksmiley.jpg
MoD
Cytat(MStaniszczak @ 2005-02-28 04:21:48)
Hmmm.... wykonanie ereg zajmuje nieco czasu (jak to wyrażeń regularnych). [...]

Szczerze mówiąc, to wolę stracić tą sekundę w czasie wykonywania skryptu niż stracić na bezpieczeństwie. I mniejszy bałagan w kodzie - jedna funkcja zamiast szeregu IF. A wyrażenie regularne można w razie czego łatwo zmodyfikować jeśli się znajdzie błąd.
tarlandil
IMHO dosc wygodna i bezpieczne rozwiazanie:
  1. <?php
  2.  
  3. function CheckValue($type,$v,$default=&#092;"\")
  4. {
  5. if (!function_exists(&#092;"CheckValue_$type\")) return \"\";
  6. $func=&#092;"CheckValue_$type\";
  7. return $func($v,$default);
  8. }
  9.  
  10. function SQLValue($type,$v,$default=&#092;"\")
  11. {
  12. if (!function_exists(&#092;"SQLValue_$type\")) return \"\";
  13. $func=&#092;"SQLValue_$type\";
  14. return $func($v,$default);
  15. }
  16. ?>


a potem definiujemy swoje funckje sprawdzajace
  1. <?php
  2.  
  3. function CheckValue_int($v,$default=&#092;"\")
  4. {
  5. if (!is_numeric($v)) return (int)$default;
  6. return (int) $v;
  7. }
  8.  
  9. function SQLValue_int($v,$default=&#092;"\")
  10. {
  11. return CheckValue_int($v,$default);
  12. }
  13.  
  14. function CheckValue_ident($v,$default=&#092;"\")
  15. {
  16. $v=trim($v);
  17. if (!preg_match(&#092;"/^([wd]+)$/\",$v)) return $default;
  18. return $v;
  19. }
  20.  
  21. function SQLValue_ident($v,$default=&#092;"\")
  22. {
  23. $v=CheckValue_ident($v,$default);
  24. $v=addslashes($v);
  25. return &#092;"'$v'\";
  26. }
  27.  
  28. function CheckValue_text($v,$default=&#092;"\")
  29. {
  30. $v=trim($v);
  31. $v=htmlspecialchars($v,ENT_QUOTES);
  32. return $v;
  33. }
  34.  
  35. function SQLValue_text($v,$default=&#092;"\")
  36. {
  37. $v=CheckValue_text($v,$default);
  38. $v=addslashes($v);
  39. return &#092;"'$v'\";
  40. }
  41.  
  42. itd..
  43.  
  44. ?>


a wykoanie zapytania np tak:
  1. <?php
  2.  
  3. $result=$sql->SendQuery(sprintf(
  4. &#092;"select * from przedmiot where id=%s and parent=%s;\",
  5. SQLValue(&#092;"ident\",$GLOBALS[\"id\"]),
  6. SQLValue(&#092;"ident\",$GLOBALS[\"parent\"])
  7. ));
  8.  
  9. ?>


I w ten sposob nawet przy braku magic quotes czy tez mozliwosci wielu zapytan w jednemy poleceniu, nikt nie przepcha zadnego zlosliwego kodu.
Jarod
Cytat(Vengeance @ 2005-02-27 13:44:07)
przez mysql_query() nie. ale funckje postgreSQL już to dopuszczają :/
Dlatego userzy tego drugiego mają większy problem.

Co do zabezpieczenia, nie wiem czym się tak przejmujecie? ;]
Ja stosuje jedynie addslashes() oraz usuwam slowo 'UNION' ze zmiennych

Cytat
przez mysql_query() nie. ale funckje postgreSQL już to dopuszczają :/
Dlatego userzy tego drugiego mają większy problem.

A jak go rozwiązać?
Cytat
Co do zabezpieczenia, nie wiem czym się tak przejmujecie? ;]
Ja stosuje jedynie addslashes() oraz usuwam slowo 'UNION' ze zmiennych

Przecież addslashes() to tosamo co mysql_escape_string() worriedsmiley.gif
sobstel
Cytat(J4r0d @ 2005-05-08 17:11:33)
Cytat(Vengeance @ 2005-02-27 13:44:07)
przez mysql_query() nie. ale funckje postgreSQL już to dopuszczają :/
Dlatego userzy tego drugiego mają większy problem.

Co do zabezpieczenia, nie wiem czym się tak przejmujecie? ;]
Ja stosuje jedynie addslashes() oraz usuwam slowo 'UNION' ze zmiennych

Cytat
przez mysql_query() nie. ale funckje postgreSQL już to dopuszczają :/
Dlatego userzy tego drugiego mają większy problem.

A jak go rozwiązać?
Cytat
Co do zabezpieczenia, nie wiem czym się tak przejmujecie? ;]
Ja stosuje jedynie addslashes() oraz usuwam slowo 'UNION' ze zmiennych

Przecież addslashes() to tosamo co mysql_escape_string() worriedsmiley.gif

1. np. mozna przefiltrowac ciag wyrzucajac wszelkie sredniki

2. funkcja nie sa sobie rownoznaczne

mysql_real_escape_string() 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).
johnson
Cytat(J4r0d @ 2005-05-08 16:40:02)
Więc, które rozwiązanie bezpieczniejsze? Stosować addslashes() ?

Nie rozumiem o co Wam chodzi z tym addslashes().
Czy chodzi o podwójne stosowanie addslashes()?
Raz przecież robi to samo php. Otrzymując dane z formularzy dostajemy postać:
To jest \"smaczny deser\"
Czy trzeba to jeszcze raz potraktować addslashes() i otrzymać:
To jest \\\"smaczny deser\\\"
i dopiero wtedy wrzucać do bazy? Już od dawna mnie frapuje ten problem smile.gif czy może ktoś to wyjaśnić?
sobstel
addslashes() (jeden raz!!!) powinno w zupelnosci wystarczyc. przy sotsowaniu mysql_escape_string moze sie pojawic porblem przy wyciganiu danych z bazy i stosowaniu stripslashes()
Peter Riley
Smieszne sa te wasze rozwazania, nie szkoda czasu?
Przypomina mi to wiare w zabobony.
Addslashes zalatwia calkowice sprawe, sprobujcie sie wlamac bez mozliwosci uzycia apostrofu. Mozecie wpisywac UNION, srednik i co tylko chcecie, ale to nic nie da, bo i tak co najwyzej zostanie wciagniete do bazy jako czesc stringa.
Do liczb is_numeric i wystarczy.
Jarod
Cytat
Nie rozumiem o co Wam chodzi z tym addslashes().
Czy chodzi o podwójne stosowanie addslashes()?


Chodzi o to, że slash dodawany jest jeżeli włączona jest jakaś opcja (już nie pamiętam o jaką chodziło - szukaj na pierwszej stronie tego topicu).
A jak dodadsz addslashes() to nawet jak dodawanie slasha jest wyłączone to ty massz pewność.

Cytat
Smieszne sa te wasze rozwazania, nie szkoda czasu?
Przypomina mi to wiare w zabobony.

Bezpieczeństwo - szkoda czasu? worriedsmiley.gif Nie dla mnie :roll2:
Cytat
Addslashes zalatwia calkowice sprawe, sprobujcie sie wlamac bez mozliwosci uzycia apostrofu. Mozecie wpisywac UNION, srednik i co tylko chcecie, ale to nic nie da, bo i tak co najwyzej zostanie wciagniete do bazy jako czesc stringa.
Do liczb is_numeric i wystarczy.

Skoro tak mówisz to będę tak robił. Jaby co to wiemy do kogo z pretensjami tongue.gif

Dziękuje za odpowiedź i pozdrawiam
Peter Riley
Cytat(J4r0d @ 2005-05-08 16:56:50)
Bezpieczeństwo - szkoda czasu?  worriedsmiley.gif  Nie dla mnie :roll2:

A co z bezpieczenstwem ma wspolnego kasowanie ciagow typu UNION ze zmiennej, w ktorej i tak kazdy apostrof zostanie wysleszowany? Nic.
addslash lub magic quote zalatwia calkowicie sprawe sql injection, oczywiscie pozostaje sprawdzenie czy nadeslane dane mieszcza sie w dozwolonym zakresie, ale to juz inna historia.
Jarod
Cytat(Peter Riley @ 2005-05-08 17:43:03)
oczywiscie pozostaje sprawdzenie czy nadeslane dane mieszcza sie w dozwolonym zakresie, ale to juz inna historia.

Możesz rozwinąć?
Peter Riley
Cytat(J4r0d @ 2005-05-08 18:08:08)
Cytat(Peter Riley @ 2005-05-08 17:43:03)
oczywiscie pozostaje sprawdzenie czy nadeslane dane mieszcza sie w dozwolonym zakresie, ale to juz inna historia.

Możesz rozwinąć?

Po prostu musimy sprawdzic, czy przeslane wartosci maja odpowiedni przedzial, czyli np. wpisana ilosc sztuk nie przekracza stanu magazynu. W przypadku wartosci tekstowych mozna porownac wyszukac ciagu w zadeklarowanej wczesniej tablicy lub uzyc switch of. Jednak to wszystko nie ma nic wspolnego ze sql injection, przed ktorym pelna obrone zapewnia defaultowa konfguracja php, a jesli wylaczymy magic quote, pozostanie addslashes.
sobstel
Cytat(Peter Riley @ 2005-05-08 18:43:03)
addslash lub magic quote zalatwia calkowicie sprawe sql injection

smiem twierdzic ze jest to zbyt odwazne stwierdzenie. wyobraz sobie taka sytuace :

URL: www.strona.php?articleid=12
filtrujemy: $id = addslashes($_GET['articleid'])
wstawiamy w zapytanie : query = 'SELECT * FROM articles WHERE id='.$id;

i teraz np. URL www.strona.php?articleid=12 OR 1

jak widzisz w tym przykladzie (co prawda dosc naiwnym) addslashes nie zalatwilo sprawy...
Kinool
panowie!!!!

juz ktos pisal o tym ze wiemy co "spodziewamy" sie otrzymac jesli chodzi o liczby to nie addslashes tylko intval() lub settype()

$id = intval($_GET['articleid']);

i jesli gosc wklepie tam cokolwiek to i tak bedzie zutowane na liczbe
nawet ze wzglegow optymalizacji lepiej jest wykonac zapytanie
SELECT * FROM table WHERE id=10
niz
SELECT * FROM table WHERE id='10'
poniewaz MySQL nie musi robic konwersji

addslashes uzywamy jesli mamy doczynienia z wartosciami textowymi lub mieszanymi

tak na marginesie to zadna funkcja nie zwalnia od myslenia!
Peter Riley
Cytat(sopel @ 2005-05-08 21:14:33)
smiem twierdzic ze jest to zbyt odwazne stwierdzenie.

To chyba oczywiste, ze musimy sprawdzic czy liczby rzeczywiscie sa liczbami, przy okazji sprawdzajac ich zakres. Zreszta pisalem o tym wyzej. Dodam tylko, ze ja sklaniam sie raczej do sprawdzania typu, a nie konwersji na sile. Jesli typ sie nie zgadza, to mail do admina i die().

Nie jest to odwazne stwierdzenie tylko fakt. Zaloze sie, ze ci co usuwaja UNION i sredniki z ciagow, na wszelki wypadek klikaja "zastosuj" w windowsowych okienkach tuz przed kliknieciem "ok" :-)
ktuvok
Dorzucę się do tego wątku i powiem, że moim zdaniem najlepszym zabezpieczeniem jest:

1. ustawienie w php.ini opcji get_magic_quotes_gpc na ON

2. stosowana równolegle z powyższym funkcja czyszcząca otrzymane dane - od razu uprzedzam, że wbrew nazwie nie dotyczy ona tylko danych przesyłanych metodą POST:
  1. <?php
  2.  
  3. function OczyscPost($Zmienna, $Rozmiar)
  4. {
  5. {
  6. $Zmienna = stripslashes($Zmienna);
  7. }
  8. $Zmienna = trim(strip_tags(str_replace(&#092;"\"\", \"\", $Zmienna)));
  9. $Zmienna = substr(str_replace(&#092;"'\",\"\", $Zmienna),0,$Rozmiar);
  10. $Zmienna = sprintf(&#092;"%s\",$Zmienna);
  11. return $Zmienna;
  12. }
  13.  
  14. ?>


3. Funkcja zapewniająca dodatkowe filtrowanie dla identyfikatorów, przekazywanych w URL'u:
  1. <?php
  2.  
  3. function DoCyfry($Zmienna)
  4. {
  5. $Zmienna = intval($Zmienna);
  6. if(is_int($Zmienna))
  7. {
  8. return $Zmienna;
  9. }
  10. else
  11. {
  12. return 0;
  13. }
  14. }
  15.  
  16. ?>


Zastosowanie:
  1. <?php
  2.  
  3. $Nazwisko = OczyscPost($_POST['Nazwisko'], 40);
  4. $ID = DoCyfry(OczyscPost($_GET['ID'], 10));
  5.  
  6. ?>


Jakieś uwagi?

Pozdrawiam,
K
Vengeance
Cytat(Peter Riley @ 2005-05-08 19:43:03)
Cytat(J4r0d @ 2005-05-08 16:56:50)
Bezpieczeństwo - szkoda czasu?  worriedsmiley.gif  Nie dla mnie :roll2:

A co z bezpieczenstwem ma wspolnego kasowanie ciagow typu UNION ze zmiennej, w ktorej i tak kazdy apostrof zostanie wysleszowany? Nic.
addslash lub magic quote zalatwia calkowicie sprawe sql injection, oczywiscie pozostaje sprawdzenie czy nadeslane dane mieszcza sie w dozwolonym zakresie, ale to juz inna historia.

Hyh... kompletnie się z Tobą nie zgodzę :]

Union da się wiele razy wykorzystać nie stosując nawet jednego apostrofu!
Więc samo używanie addslashes() w przypadku posiadania MySQL 4 nie jest bezpieczne !
bolas
a takie pytanko jeszcze.
czy umozliwienie stosowania wszystkich znakow np. spacji przy tworzeniu loginu podczas rejestracji jest niebezpieczne ?
bolas
wszystkie znaki - oczywiscie przy wlaczanej dyrektywie gpc_magic_quotes

ktuvok - uzywam podobnego mechanizmu i na razie nie ma problemow (moze dlatego, ze nikt nie robil testow, albo nie zauwazono, ze cos jest nie tak). dodatkowo uzywam htmlspecialchars.
kubatron
Nie wiem czy był dawany ten link lecz jeśli nie to prosze o usunięcie postu, a takto ciekawy art do przeczytanie http://www.computerworld.pl/artykuly/31505.html
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-2021 Invision Power Services, Inc.