Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Bezpieczeństwo skryptów PHP
Forum PHP.pl > Forum > PHP
Stron: 1, 2, 3, 4, 5, 6, 7
Diwi
Witam.

Chciałbym rozpocząć temat o bezpieczeństwie skryptów php. Na forum istnieje już temat o bezpieczeństwu przy wykonywaniu zapytania SQL lecz nie ma o ogólnym bezpieczeństwie skryptów.

1. Złe używanie include.

Często dołączamy pliki dynamicznie pobierając miejsce gdzie znajduje się plik metodą GET.

Przykładowy adres:
http://www.jakas-strona.pl/index.php?plik=katalog.php

Kod php:
  1. <?php
  2. include($_GET['plik']);
  3. ?>


Taki skrypt dokonałby dołączenia pliku katalog.php do skryptu lecz co by się stało gdyby włamywacz wpisał taki adres:
http://www.jakas-strona.pl/index.php?plik=...t-niszczacy.php

Dajmy na to że skrypt znajdujący się na serwerze hakera wygląda tak:

  1. <?php
  2.  
  3. $katalog = opendir('./'); /* skrypt otwiera katalog w którym się znajduje (zostaje wywołany */
  4.  
  5. while ($plik = readdir($katalog)) {
  6.  
  7. unlink($file);
  8.  
  9. }
  10.  
  11. ?>


No i jeżeli pliki w katalogu mają uprawnienia pozwalające na usunięcie ich przez skrypt to możemy się pożegnać z plikami w katalogu.

Jak temu zapobiec questionmark.gif

Rozwiązanie 1.

Tworzymy taki include:
  1. <?php
  2. include('./'.$_GET['katalog']);
  3. ?>


Taka instrukcja pozwala na dołączanie jedynie plików które znajdują się w katalogu ze skryptem czyli nie można załączyć pliku z innego serwera.

Ja narazie pamiętam tylko tyle lecz jeżeli znacie jakieś inne błędy popełniane przez programistów a także sposoby walczenia z nimi to się tutaj dopiszcie smile.gif

Pozdrawiam

// prosiłbym moderatorów (jeżeli można) o przyklejenie tego tematu

---
Przyklejone - hwao
bregovic
Zaczynając od podstaw, to jakiekolwiek używanie zmiennej $_GET razem z konstrukcja require lub include jest pomyłką, błędem i koszmarem. Jeśli już naprawdę musisz include'ować coś pochodzącego z adresu, to zrób sobie tablicę w skrypcie, coś w stylu:
  1. <?php
  2.  
  3. $tablica[1] = 'jakisplik1';
  4. $tablica[2] = 'jakisplik2';
  5. $tablica[3] = 'jakisplik3';
  6. $tablica[4] = 'jakisplik4';
  7.  
  8. include $tablica[$_GET['costam']];
  9.  
  10. ?>


Oczywiście to rozwiązanie jest koszmarkiem jeśli masz dużą ilość akcji - wtedy trzeba zrobic cos w tym stylu:
  1. <?php
  2.  
  3.  
  4. if(file_exist('bezpieczny_katalog/'.$_GET['costam'].'.php'))
  5. {
  6. include 'bezpieczny_katalog/'.$_GET['costam'].'.php';
  7. }
  8.  
  9. ?>


Generalna zasada to zawsze zakładać że input inny niż tego chcemy, i że user próbuje nas zaatakować. winksmiley.jpg
Wave
A najczęstszym błędem jest stosowanie zmiennych bez odnoszenia się do tablic superglobalnych.
np.
  1. <?php
  2.  
  3. $var; // zamiast
  4. $_COOKIE['var'];
  5. $_POST['var'];
  6. $_GET['var'];
  7. $_SESSION['var'];
  8.  
  9. ?>

Co daje pole do popisu, dla potencjalnego hax0ra.
Jeżeli nie chce nam się pisać tych długich zmiennych można zastosować coś takiego:
  1. <?php
  2.  
  3. while (list($k, $v) = each ($_GET)) {
  4. ${$k} = $v;
  5. }
  6.  
  7. ?>


----
Sorka ze sie dopisze ale smile.gif nie chce mi sie pisac nowego posta smile.gif)

Jak komus sie nie che to polecam
  1. <?php
  2. $g = & $_GET;
  3. // i mammy
  4. $g['id'];
  5.  
  6. ?>

sobstel
Cytat(bregovic @ 2005-05-05 15:49:34)
Zaczynając od podstaw, to jakiekolwiek używanie zmiennej $_GET razem z konstrukcja require lub include jest pomyłką, błędem

a na przyklad w takiej konstrukcji :

  1. <?php
  2.  
  3. if (ctype_alnum($_GET['go'])) {
  4. include $_GET['go'].'.php';
  5. }
  6.  
  7. ?>


questionmark.gif?

tak czy owak moim zdaniem najwazniejsze w tym wszyskim jest odpowiednie filtrowanie wszystkiego co pochodzi z zewnątrz lub w czym zewnętrzny użytkownik mógł maczać palce ... i zdawać sobie sprawę z tego, że nigdy nei jesteśmy w pełni bezpieczni.
Speedy
To ja dodam od siebie jeszcze, że niektóre osoby pisząc aplikacje internetowe, stosują coś takiego jak przechowywanie poufnych danych o userze (po zalogowaniu) w pliku cookie. Taki potencjalny H4X0R może sobie potem swobodnie przeglądać zawartość tych plików i dowolnie je modyfikować. Najgorzej jest wtedy, gdy w takim pliku przechowywana jest wartość zmiennej odpowiedzialna np. za uprawnienia administratora... Wtedy wystarczy ją odpowiednio podmienić i śmiga winksmiley.jpg .
Rozwiązaniem są sesje, które przechowują dane na serwerze.

Pozdrawiam.
yavaho
Mozna nieco przefiltrowac zmiena ktora pzechowuje nazwe dolaczanego pliku. I jezeli jest to plik z innej domeny to adres zostanie nieco zmodyfikowany na tyle ze nie zostanie znaleziony.
  1. <?php
  2. if(isset($_GET['page'])){
  3. $page = ereg_replace(&#092;"://\",\"#\",$_GET['page']);
  4. }else{
  5. $page='glowna';
  6. }
  7. ?>
Mozna jeszcze wszystkie includowane pliki przechowywac w jakims jednym katalogu i przed wywolaniem takiego pliku zawsze do zmiennej bedzie dolepiona sciezka co zmieni "niechciane linki" . Mozna tez sprawdzic czy includowany plik napewno pochodzi z naszej domeny basename()" title="Zobacz w manualu PHP" target="_manual
  1. <?php
  2. if(file_exists('skrypty/'.$page.'.php')){
  3. include ('skrypty/'.basename($page.'.php'));
  4. }else{
  5. include ('skrypty/glowna.php');
  6. }
  7. ?>
Po takiej filtracji ja bym sie czul zupelnie spokojnie.

@Speedy czasem musimy cos zostawic w ciasteczku aby rozpoznac danego uzytkownika. Np podczas stosowania autologinu do panelu admina - i tu niestety jest niebezpieczenstwo, na ktore ja nie znam jeszcze dobrego zabezpieczenia.
matid
Cytat(yavaho @ 2005-05-08 16:03:31)
@Speedy czasem musimy cos zostawic w ciasteczku aby rozpoznac danego uzytkownika. Np podczas stosowania autologinu do panelu admina - i tu niestety jest niebezpieczenstwo, na ktore ja nie znam jeszcze dobrego zabezpieczenia.

A nie wystarczy czasem skorzystać z funkcji session_set_cookie_params" title="Zobacz w manualu PHP" target="_manual ?
sobstel
Cytat(matid @ 2005-05-08 17:06:28)
Cytat(yavaho @ 2005-05-08 16:03:31)
@Speedy czasem musimy cos zostawic w ciasteczku aby rozpoznac danego uzytkownika. Np podczas stosowania autologinu do panelu admina - i tu niestety jest niebezpieczenstwo, na ktore ja nie znam jeszcze dobrego zabezpieczenia.

A nie wystarczy czasem skorzystać z funkcji session_set_cookie_params" title="Zobacz w manualu PHP" target="_manual ?

Efekt działania tej funkcji widoczny jest tylko do końca działania skryptu.
Ociu
sprawdzanie $_GET'ów etc. :
  1. <?php
  2. if(is_int($_GET['id']))
  3. ?>


Wave: lepiej używać foreach.
vala
a nie lepiej zrobic prosty switch ?
ustalimy sobie wtedy wszystkie dostepne przypadki i lux

o cos takiego :
  1. <?php
  2.  
  3.  
  4. if(isset($_GET['id']))
  5. {
  6. switch($_GET['id'])
  7. {
  8.  case &#092;"newsy\":
  9.  case &#092;"smieci\": $ref=$_GET['id'];break;
  10.  
  11.  default: $ref=&#092;"newsy\";
  12.  
  13.  }
  14.  
  15. include(&#092;"katalog/\".$ref.\".php\");
  16.  
  17. }
  18.  
  19.  
  20. ?>
AxZx
Cytat(vala @ 2005-05-14 17:52:01)
a nie lepiej zrobic prosty switch ?
ustalimy sobie wtedy wszystkie dostepne przypadki i lux

o cos takiego :
  1. <?php
  2.  
  3.  
  4. if(isset($_GET['id']))
  5. {
  6. switch($_GET['id'])
  7. {
  8.  case &#092;"newsy\":
  9.  case &#092;"smieci\": $ref=$_GET['id'];break;
  10.  
  11.  default: $ref=&#092;"newsy\";
  12.  
  13.  }
  14.  
  15. include(&#092;"katalog/\".$ref.\".php\");
  16.  
  17. }
  18.  
  19.  
  20. ?>

@Vala - mozna to zrobic tak, wtedy nie trzeba dawac if(isset(....

  1. <?php
  2.  
  3.  
  4.  
  5. switch(@$_GET['id'])
  6. {
  7.  case &#092;"newsy\":
  8.  case &#092;"smieci\": $ref=$_GET['id'];break;
  9.  
  10.  default: $ref=&#092;"newsy\";
  11.  
  12.  }
  13.  
  14. include(&#092;"katalog/\".$ref.\".php\");
  15.  
  16.  
  17.  
  18.  
  19.  
  20. ?>
sobstel
Cytat(AxZx @ 2005-05-21 12:24:56)
@Vala - mozna to zrobic tak, wtedy nie trzeba dawac if(isset(.

trzeba jesli nie chcemy aby pojawial sie nam blad typu E_NOTICE kiedy id nie bedzie w adresie (najczesciej jest to strona glowna). ewentualnie mozna wczesniej umiescic sprawdzenie if (!isset($_GET['id']) $ref="newsy";
Lars
ja mam prosty skrypt:
  1. <?php
  2. if(isset($_GET['mod'])) {
  3. $mod=$_GET['mod'];
  4. } else {
  5. $mod=&#092;"news\";
  6. }
  7.  
  8. if(isset($_GET['act'])) {
  9. $act=$_GET['act'];
  10. } else {
  11. $act=&#092;"list\";
  12. }
  13.  
  14. $file=$mod.'/'.$act.'.php';
  15.  
  16. if(!file_exists($file)) {
  17. die();
  18. } else {
  19. include &#092;"$file\";
  20. }
  21. ?>


czy file_exists zabezpiecza includowanie z innego serwera??
sobstel
Cytat(Lars @ 2005-07-01 08:45:41)
czy file_exists zabezpiecza includowanie z innego serwera??

tak, ale "Od wersji 5.0.0 php ta funkcja może być użyta także z niektórymi wrapperami URL."
yavaho
Cytat
czy file_exists zabezpiecza includowanie z innego serwera??
Tak, ale tylko w przypadku gdy prawdziwa nazwa includowanego pliku lub sciezka do niego bedzie nieco inna niz ta przekazywana w zmiennej.

W tym przypadku wszystkie includowane pliki musza znajdowac sie w odpowiednim katalogu.
  1. <?php
  2. if(!file_exists('katalog/'.$file.'.php')) {
  3. die();
  4. } else {
  5. include('katalog/'.$file.'.php');
  6. }
  7. ?>

W tym przypadku wszystkie includowane pliki musza miec specyficzny jednakowy poczatek nazwy pliku.
  1. <?php
  2. if(!file_exists('inc_'.$file.'.php')) {
  3. die();
  4. } else {
  5. include('inc_'.$file.'.php');
  6. }
  7. ?>

I jezeli w zmiennej przekaze ktos sciezke do innego serwera to taki plik nie zostanie znaleziony.
gu35t
pamietejcie o zonku jaki moze zrobic haxior znakiem pustym:
czyli mam taki np kodzik:
  1. <?php
  2. if(....){
  3. include './skrypty/' . $_GET['plik'] . '.php';
  4. }
  5. ?>

haxior moze wpisac cos takiego
index.php?plik=../../../../../../../etc/passwd%00
czyli:
include ./skrypty/../../../../../../../etc/passwd%00.php no i sie nam pieknie otwarl plik
dobra wiadomosc: znak pusty(\0 == %00) juz na malo jakim serwerze dziala ale czasami znajde. winksmiley.jpg
to znalalem w przeciagu 2 min na google:
http://www.nfz-krakow.pl/index.php?plik=ko..../../etc/passwd
http://www-users.mat.uni.torun.pl/~ghost/i..../../etc/passwd
sobstel
1. kolega pytal tylko czy mozna otworzyc w ten sposob zewnetrzne pliki tongue.gif
2. mysle ze uzycie file_exists() i basename() jest dobrym sposobem na dolaczanie plikow, ale jak jest ich stosunkowo niewiele zawsze najlepiej zrobic switcha
3. co do zanku pustego to dziala tam gdzie jest wylaczone automatyczne magic_quotes i ktos nie zabezpieczyl tego samemu
Lars
co do: http://www-users.mat.uni.torun.pl/~ghost/i..../../etc/passwd

to można to zabezpieczyć:

  1. <?php
  2. ....przed includem
  3.  
  4. $_GET['plik']=str_replace(&#092;"/\", \"#\", $_GET['plik']);
  5.  
  6. include $_GET['plik'];
  7.  
  8. dalej....
  9. ?>


prosty przykład filtrowania danych happy.gif
sobstel
Cytat(Lars @ 2005-07-03 19:52:24)
co do: http://www-users.mat.uni.torun.pl/~ghost/i..../../etc/passwd

to można to zabezpieczyć:

  1. <?php
  2. ....przed includem
  3.  
  4. $_GET['plik']=str_replace(&#092;"/\", \"#\", $_GET['plik']);
  5.  
  6. include $_GET['plik'];
  7.  
  8. dalej....
  9. ?>


prosty przykład filtrowania danych happy.gif

ja mimo wszystko upieralbym sie przy basename" title="Zobacz w manualu PHP" target="_manual()
Vengeance
@bregovic:

Twój sposób
  1. <?php
  2.  
  3. $tablica[1] = 'jakisplik1';
  4. $tablica[2] = 'jakisplik2';
  5. $tablica[3] = 'jakisplik3';
  6. $tablica[4] = 'jakisplik4';
  7.  
  8. include $tablica[$_GET['costam']];
  9.  
  10. ?>


Też nie jest bezpieczny... dajmy na to wywołam URL:
/skrypt.php?tablica[foobar]=haxiorskiPlik&costam=foobar

Oczywiscie zagrozenie wynika glownie wtedy gdy mamy dostep do zrodel... choc czasem da sie takze zgadnac nazwy zmiennych
dr_bonzo
A wystarczy dodac
$tablica = array();
przed jej uzyciem i po klopocie.
A poza tym to bylo tylko
Cytat
to zrób sobie tablicę w skrypcie, coś w stylu
, pisane szybko i bez doglebnego zastanowienia biggrin.gif
Lars
Jeżeli już trzeba zrobić coś takiego:

  1. <?include $_GET['id'].'.php';?>


to zawsze lepiej:

  1. <?php
  2. $file=$_GET['id'].'.php';
  3. if(file_exists($file)) {
  4. include $file;
  5. } else {
  6. echo 'Błąd 404';
  7. }
  8. ?>


Jest jeszcze coś takiego (działą tylko z rg=on).

Mamy kod:
  1. <?php
  2. <form action='ksiega.php' method='post'>
  3. <input type='text' name='nick' value='twoj nick'>
  4. <textarea name='tekst'>Twoj tekst</textarea>
  5. <input type='submit' value='Wyslij'>
  6. </form>
  7. ?>


i plik ksiega.php:

  1. <?php
  2. $file=fopen('data.txt', a);
  3. $zawartosc='<b>'.$nick.'</b><br>'.$tekst.'<br><br>';
  4. fwrite($file, $zawartosc);
  5. fclose($file);
  6. echo 'OK. <a href=\"javascript:history.back()\">Wróć</a>';
  7. ?>


jest tu bardzo wiele luk, m. in:
  • 1. Możliwość wstawienia dowolnej długości nicka/tekstu
  • 2. Umieszczanie kodu !!html!!
  • 3. wpis danych przez ?nick=nick&tekst=txt
  • 4. możliwość uszkodzenia pliku data.txt przez wpisywanie sie przez 2 osoby w tym samym momencie
  • 5. użycie kodu php
jak je usunąć??

1. Użycie strlen" title="Zobacz w manualu PHP" target="_manual:
  1. <?php
  2. $file=fopen('data.txt', a);
  3. $nick=stripslashes($nick);
  4. $tekst=stripslashes($tekst);
  5. if(strlen($nick>10)) {
  6. die('Za długi nick');
  7. } elseif(strlen($tekst>100)) {
  8. die('Za długi tekst');
  9. }
  10. $zawartosc='<b>'.$nick.'</b><br>'.$tekst.'<br><br>';
  11. fwrite($file, $zawartosc);
  12. fclose($file);
  13. echo 'OK. <a href=\"javascript:history.back()\">Wróć</a>';
  14. ?>


2. Użycie strip_tags" title="Zobacz w manualu PHP" target="_manual:
  1. <?php
  2. $file=fopen('data.txt', a);
  3. $nick=stripslashes($nick);
  4. $tekst=stripslashes($tekst);
  5.  
  6. $nick=strip_tags($nick);
  7. $tekst=strip_tags($tekst);
  8.  
  9. if(strlen($nick>10)) {
  10. die('Za długi nick');
  11. } elseif(strlen($tekst>100)) {
  12. die('Za długi tekst');
  13. }
  14. $zawartosc='<b>'.$nick.'</b><br>'.$tekst.'<br><br>';
  15. fwrite($file, $zawartosc);
  16. fclose($file);
  17. echo 'OK. <a href=\"javascript:history.back()\">Wróć</a>';
  18. ?>


3. Zamiast $tekst/$nick używamy $_GET['tekst']/$_GET['nick']:
  1. <?php
  2. $file=fopen('data.txt', a);
  3. $_GET['nick']=stripslashes($_GET['nick']);
  4. $_GET['tekst']=stripslashes($_GET['tekst']);
  5. $_GET['nick']=strip_tags($_GET['nick']);
  6. $_GET['tekst']=strip_tags($_GET['tekst']);
  7.  
  8. if(strlen($_GET['nick']>10)) {
  9. die('Za długi nick');
  10. } elseif(strlen($_GET['tekst']>100)) {
  11. die('Za długi tekst');
  12. }
  13. $zawartosc='<b>'.$_GET['nick'].'</b><br>'.$_GET['tekst'].'<br><br>';
  14. fwrite($file, $zawartosc);
  15. fclose($file);
  16. echo 'OK. <a href=\"javascript:history.back()\">Wróć</a>';
  17. ?>


4. Użycie flock" title="Zobacz w manualu PHP" target="_manual:
  1. <?php
  2. $file=fopen('data.txt', a);
  3. $_GET['nick']=stripslashes($_GET['nick']);
  4. $_GET['tekst']=stripslashes($_GET['tekst']);
  5. flock($file, 2);
  6. $_GET['nick']=strip_tags($_GET['nick']);
  7. $_GET['tekst']=strip_tags($_GET['tekst']);
  8.  
  9. if(strlen($_GET['nick']>10)) {
  10. die('Za długi nick');
  11. } elseif(strlen($_GET['tekst']>100)) {
  12. die('Za długi tekst');
  13. }
  14. $zawartosc='<b>'.$_GET['nick'].'</b><br>'.$_GET['tekst'].'<br><br>';
  15. fwrite($file, $zawartosc);
  16. flock($file, 3);
  17. fclose($file);
  18. echo 'OK. <a href=\"javascript:history.back()\">Wróć</a>';
  19. ?>


5. To to samo co w punkcie 2 tongue.gif.
Vaticinator
A jest jakaś możliwość, żeby wybrane pliki dało się otwierać tylko poprzez include(), a nie bezpośrednio z przeglądarki?
sobstel
Cytat(Vaticinator @ 2005-09-16 11:21:56)
A jest jakaś możliwość, żeby wybrane pliki dało się otwierać tylko poprzez include(), a nie bezpośrednio z przeglądarki?

jest, na szybko przychodzą mi do glowy 2 sposoby :

1. umiescic pliki w jakims katalogu i zabezpieczyc plikiem .htaccess z odpowiednim wpisem (deny from all)
2. umiescic pliki powyzej public_html
bregovic
Cytat(Vaticinator @ 2005-09-16 11:21:56)
A jest jakaś możliwość, żeby wybrane pliki dało się otwierać tylko poprzez include(), a nie bezpośrednio z przeglądarki?

Plik includeujący:
  1. <?php
  2.  
  3. define('x', true);
  4. include 'lol.php';
  5.  
  6. ?>


Plik lol.php:
  1. <?php
  2.  
  3. if(!x) die();
  4. //reszta pliku
  5.  
  6. ?>
mike

W związku z ostatnim postem tutaj, który poruszał problem już omówiony postanowiłem trochę oczyścić ten wątek.

Kilka postów zostało usuniętych - zostały te które powinny zostać tongue.gif

Od tej chwili, proszę użytkowników zwłaszcza początkujących o czytanie tego wątku od początku a nie tylko dopisywanie się na końcu bez czytania całości tego wątku.

Czasem (a raczej często) rozwiązanie problemu jaki macie już padło. Warto poświęcić czas na odszukanie rozwiązania.

P.S.
To nie jest kącik lamerskich pytańexclamation.gif!
huntercs
Ja stosuję w sumie proste rozwiązanie, dodaje tylko strony do których użytkownik może wejść i tyle, jeżeli chce wejść na inną to jest przekierowany na str. główną
  1. <?php
  2. $Section=$_GET['Section'];
  3.  
  4. if($Section!='Main' &&
  5. $Section!='Activate' &&
  6. $Section!='Kolejna_strona' &&
  7. $Section!='Inna_strona' &&
  8. $Section!='Regulamin')
  9. header("Location: ?Section=Main");
  10. else include_once($Section.".php");
  11. ?>
nospor
No ale poco trzeba pisac nazwe skryptu? Skoro i tak juz to oifowales, to daj identyfikator a nie nazwe. Po co ktoś ma wiedziec jakie masz skrypty?
mike
~huntercs możesz to zrobić bardziej elastycznie i elegancko:
  1. <?php
  2.  
  3. $_GET[ 'Section' ] = ( empty( $_GET[ 'Section' ] ) ) ? 'Main' : '';
  4.  
  5. $arrAllowSection = array(
  6. 'Main' => 'Main.php',
  7. 'Activate' => 'Activate.php',
  8. 'Inna_strona' => 'Inna_strona.php',
  9. 'Regulamin'  => 'Regulamin.php'
  10. );
  11.  
  12. if( in_array( $_GET[ 'Section' ], $arrAllowSection ) )
  13. {
  14. include_once( $arrAllowSection[ $_GET[ 'Section' ] ] );
  15. }
  16. else
  17. {
  18. include_once( $arrAllowSection[ 'Main' ] );
  19. }
  20.  
  21. ?>


Masz teraz możliwość prostego i łatwego dodawanie stron i nie musisz ich adresów uzależniać od wartości $_GET[ 'Section' ]. Bo możesz dawać inne nazwy plików.
vedeney
I like php-coding in this way smile.gif
  1. <?php
  2. include_once(((isset($_GET[ 'Section' ]) && !empty($_GET[ 'Section' ])) && is_file(str_replace(array(".","/"),"",$_GET['Section']).".php"))?str_replace(array(".","/"),"",$_GET['Section']).".php":'Main.php');
  3. ?>


Just one line, not 21! Rkingsmiley.png
ave
nie prosciej switch-em ?
  1. <?php
  2. switch($_GET['id']){
  3. case 'aa': include('aa.php');break;
  4. case 'bb': include('bb.php');break;
  5. default:  include('main.php');
  6. }
  7. ?>
Speedy
Switch może być dobry w przypadku, gdy jest mało stron i ich ilość nie jest mobilna. Zauważ, że dla każdego pliku musisz doklepywać osobnego case'a, a można to przecież zrobić bardziej dynamicznie winksmiley.jpg.
the_foe
Jezeli programuje obiektowo to automatyzuje wybieranie stron przez wybieranie metod.
Zaluzmy ze $_GET['p'] odpowiada za podstrone:
  1. <?php
  2.  function get_page()
  3. {
  4. /*metoda zajmuje sie analizowaniem zmiennej p
  5. zgodnie z jej wartoscia przerzuca skrypt do 
  6. metody link_wartosc
  7. */
  8. if (!isset($_GET['p']))
  9. {
  10.  
  11. $this->link_index();
  12. }
  13. else
  14. {
  15. $a=strtolower($_GET['p']);
  16. $a=ereg_replace('([^a-z0-9_-])',"",$a);
  17. if ($a=="")
  18. {
  19. $this->link_index();
  20. }
  21. else
  22. {
  23. $z=method_exists($this,"link_".$a);
  24. if ($z==1)
  25. {
  26. eval('$this->link_'.$a.'();');
  27. }else{
  28. $this->error();
  29. }
  30. }
  31. }
  32.  
  33. }
  34. ?>

tworzymy wiec medtode dla linku www.domena.pl/?p=strona link_strona. W metodzie (funkcji) moze byc zwykly include.
Kiedy dana strona nie istnieje, czyli nie stworzylismy danej metody, zostanie uruchomiona metoda error(). Np strona bledu 404 ktora zaprojektujemy, albo zwykly redirector do indeksu.
LamaMASTER
Cytat(Diwi @ 2005-05-05 12:21:40)
1. Złe używanie include.

Często dołączamy pliki dynamicznie pobierając miejsce gdzie znajduje się plik metodą GET.

Przykładowy adres:
http://www.jakas-strona.pl/index.php?plik=katalog.php

Kod php:
  1. <?php
  2. include($_GET['plik']);
  3. ?>


Taki skrypt dokonałby dołączenia pliku katalog.php do skryptu lecz co by się stało gdyby włamywacz wpisał taki adres:
http://www.jakas-strona.pl/index.php?plik=...t-niszczacy.php

Dajmy na to że skrypt znajdujący się na serwerze hakera wygląda tak:

  1. <?php
  2.  
  3. $katalog = opendir('./'); /* skrypt otwiera katalog w którym się znajduje (zostaje wywołany */
  4.  
  5. while ($plik = readdir($katalog)) {
  6.  
  7. unlink($file);
  8.  
  9. }
  10.  
  11. ?>


No i jeżeli pliki w katalogu mają uprawnienia pozwalające na usunięcie ich przez skrypt to możemy się pożegnać z plikami w katalogu.

Jak temu zapobiec questionmark.gif

Rozwiązanie 1.

Tworzymy taki include:
  1. <?php
  2. include('./'.$_GET['katalog']);
  3. ?>


Taka instrukcja pozwala na dołączanie jedynie plików które znajdują się w katalogu ze skryptem czyli nie można załączyć pliku z innego serwera.

Ludzie litości! Wielkie zabezpieczenia, a ja widzę, że tu ktoś podstaw php nie zna! Od kiedy to w include idzie podać ścieżkę do innego serwera? Jeżeli podamy:
  1. <?
  2. include('http://www.domena.pl/skrypt.php');
  3. ?>

to skrypt nie zostanie zincludowany! Taka opcja jest możliwa jest jedynie w funkcji readfile (do tego właśnie ona jest).
Zastosowanie:
  1. <?
  2. include($zmienna);
  3. ?>

jest dosyć bezpieczne (zależy od skryptu). Najbardziej bezpieczne jest już:
  1. <?
  2. include('katalog/'.$zmienna.'.php');
  3. ?>

Ludzie - jak ja widzę takie bzdury, że wtedy za pomocą index.php?zmienna=http:///cośtam można zhackować stronę to mnie krew zalewa. Tak samo w przypadku tematu o SQL Injection - pierdół pełno powypisywane. Skoro już piszecie w ciemno, to najpierw polecam czy takie coś zadziała, a potem pisać jak przeciwdziałać.
W dodatku przy powyższym skrypcie jeżeli dodamy:
$zmienna = $_GET['zmienna'];
to nie stanie się nic innego jak to, że zmienna przybierze wartość z adresu 2 razy (a co za tym idzie skrypt będzie wykonywany wolniej). Pokażcie mi w tym jakąś lukę to zwracam honor...

Reszty postów i tematu całego wolę dalej nie czytać winksmiley.jpg
nospor
Cytat
Ludzie litości! Wielkie zabezpieczenia, a ja widzę, że tu ktoś podstaw php nie zna! Od kiedy to w include idzie podać ścieżkę do innego serwera?
hmmm, manual klamie?
http://pl.php.net/manual/pl/function.include.php
Cytat
Jeśli "URL fopen wrappers" są włączone w php (takie jest domyślne ustawienie) można podać nazwę pliku do wczytania używając adresu URL (przez protokół HTTP lub innym obsługiwanym sposobem - zajrzyj do Dodatek M aby zapoznać się z listą obsługiwanych protokołów), zamiast podawać ścieżkę lokalną.
Nie sprawdzalem tego nigdy, ale wierze manualowi smile.gif

edit: sprawdzilem. manual nie klamie. da sie smile.gif
Na przyszlosc jak kogos oskarżasz o brak podstaw, sprawdź, czy sam je posiadasz smile.gif

q.php
  1. <?php
  2. include($_GET['file']);
  3. ?>

a link do skryptu:
http://rpn/test/q.php?file=http://forum.webcity.pl/index.php
no i tym sposobem odpalilem se konkurencyjne forum, a teoretycznie chcialem moją stronę smile.gif

Cytat
Reszty postów i tematu całego wolę dalej nie czytać
ja rowniez ci tego nie polecam dla Twego dobra, jeszcze cię coś naprawdę zaleje winksmiley.jpg.
kszychu
A ja z kolei dodam, że3 należałoby się przyjrzeć składni include i pochodnych. Zwłaszcza polecam lekturę: jak zachowuje sieinclude pobierając pliki z innych serwerów.
Kolega LamaMASTER myli się, da się zaincludować skrypt php z innego serwera, z drobnym ale... Uważacie, że apache na tym serwerze puści na źródło skryptu, bo my go o to poprosimy?... Nie? A jak zachowa się apache?...
I obyśmy tylko takich hakerów mieli, którzy skrypt niszczący odpalają z własnego serwera :-D
LamaMASTER
Na moim serwerze taki trick nie działa, dlatego byłem przekonany, że nie idzie (tak samo było u moich kolegów).
nospor
I tylko dlatego, ze u ciebie ten trick nie dziala, to jedziesz po innych uzytkownikach? oskarżasz ich o brak wiedzy, o brak testow tego co robią, o nieczytanie manuala? Zastanow sie co robisz.

Slyszales kiedys o czymś takim, ze kazdy serwer mozna inaczej skonfigurowac?

ps: wspominales cos o zwróceniu honoru... jakos tego nie zauwazylem bys to zrobil tongue.gif
LamaMASTER
Cytat
ps: wspominales cos o zwróceniu honoru... jakos tego nie zauwazylem bys to zrobil

\/
Cytat
Pokażcie mi w tym jakąś lukę to zwracam honor


Cytat
Gdzie masz jakieś pierdoły na ten temat? Podaj przykłady, a nie świeć swoimi mądrościami.

Przykład: Skoro mamy np. mysql_query, to nie jest możliwe zrobienie czegoś takiego: news.php?id=1;DROP%20TABLE%20news; , bo mysql_query pozwala na wysłanie tylko jednego zapytania.

Poświeciłem poświeciłem i się wyświeciło winksmiley.jpg Przepraszam za zamieszanie smile.gif
Vengeance
Ale przy postgresql, mssql czy oracle to już zadziała... pamiętaj, świat nie ogranicza się do mySQL
thornag
Wracajac do powyższej dyskusji na temat include to chcialbym i cos od siebie dodac.

Założmy, że manual klamie (to tak tylko na cele posta tongue.gif) i include nie pozwala dołączać URLi z zewnatrz. Ważne jest tez, że administrator nie wpadł na takowy pomysł i nie ma poistawionego Apache'a na chroocie.

Mamy podany wyzej include o postaci:

  1. <?php
  2.  
  3. include($_GET['zmienna']);
  4.  
  5. ?>


Warto dodac ze skrypt taki umiescimy w pliku index.php

No i teraz czas na zabawe, katalogi moga byc różne w zależnosci od Linuxa u mnie na jednym serwerze z OpenBSD i Apachem na chroocie oczywiscie nie dziala ale na drugim z Red Hatem mozna sie pobawic.

Przekazujemy takie adresy

http://domena/index.php?zmienna=/etc/my.cnf (jak mowilem w zaleznosci od serwera)

i widzimy konfiguracje MySQLa, idzmy dalej

http://domena/1.php?zmienna=/etc/passwd

titaj mamy informacje o userach na serwerze

adresow do tego typu plikow mozna szukac wiecej stopien niebezpieczenstwa zależy od stopnia wiedzy intruza.

Ale to tak chcialem dorzucic bo nie lubie jak ktos pisze bzdury ze inni bzdury piszanie patrzac nawet do manuala smile.gif zachowuje sie wtedy jak moj stary smile.gif tzn chodzbym mu dowod na pismie na cos przedstawil to stary i tak uwaza ze ma racje tongue.gif

Pozdrawiam
kszychu
@thornag: dziękujemy za jakże wnikliwą analizę problemu. Zanim uraczysz nas kolejnymi rewelacjami bądź łaskaw czytać dokładnie wątki, w których się udzielasz. Jeśli nie całe to chociaż pierwsze strony.
Jarod
Co znaczy apach na chroocie?
thornag
Cytat(kszychu @ 2006-04-13 15:40:36)
@thornag: dziękujemy za jakże wnikliwą analizę problemu. Zanim uraczysz nas kolejnymi rewelacjami bądź łaskaw czytać dokładnie wątki, w których się udzielasz. Jeśli nie całe to chociaż pierwsze strony.

Wszak nawet nie smiem twierdzic ze to rewelacje chyba wiekszosc forumowiczow doskonale o tym wie. Watek czytalem acz byc moze umknely mi posty o wyswietlaniu plikow konfiguracyjnych. Pozatym nie pisze tego by raczyc rewelacjami a jedynie by pokazac tym ktorzy w nieswiadomosci zyja ze cos takiego jest mozliwe. I nawiazujac wlasnie do tego co przed momentem napisalem a dokladniej mowiac do przydatnosci posta odpwoiem na pytanie poprzednika:

chroot to taki mechanizm, ktory sprawia, ze np. Apache uznaje, że katalogiem głównym systemu jest dla niego katalog instalacji czyli np. /var/www po to by nikt nie mogl zrobic directory traversal nawet jak przejmiesz apache, to nie wyleziesz do prawdziwego katalogu. To trak w skrocie czyli tyle co sam wiem co mi przekazano smile.gif

Edit:

kszychu ==> rzeczywiscie zwracam honor, przy czytaniu umknela mi strona nr.2 moj blad jak najbardziej przyznaje racje, aczkolwiek musze zaznaczyc ze nie mialem złych zamiarow rolleyes.gif
Nightwalker
Witam,

Mam pytanie, czy ten kod jest w miare bezpieczny?

  1. <?php
  2. zapisz($_GET['sekcja']);
  3. ?>


  1. <?php
  2. function zapisz($dbs)
  3. {
  4. $plik = 'database/'.$dbs.'.dbs';
  5. $otworzplik = fopen($plik, 'w+') or die("Blad podczas otwierania!");
  6. $zapiszplik = fwrite($otworzplik, $zamiana) or die("Blad podczas zapisywania!");
  7. }
  8.  
  9. ?>


uzycie funkcji zapisz() jest w if(isset($_COOKIE["Admin"])) (jezeli cookie sie nie zgadza nie ruszy)

Zreszta podam adres skryptu http://firefoks.be/admin.php (który zresztą za niedługo opublikuje biggrin.gif)

Pozdrawiam
mumin.php
Witam

Jestem nowy na forum i zgodnie z sugestią mike_mech'a przeczytałem cały wątek. Wydaje mi się że nie znalazłem odpowiedzi na moje pytanie, więc pozwolę sobie zapytać smile.gif

Jakiś czas temu pojawił mi się problem z atakami przez formularze (np. mailowe) - we wszystkich wykorzystuję metodę $_POST. Mója znajmomość php pozwoliła mi na uzyskanie mniej więcej takiej jakości zabezpieczeń:

  1. <form id="nazwa" method="post" action="">
  2. <input type="text" name="pole_tekstowe" value="" /><br />
  3. <input type="radio" name="jakies_radio" value="wartosc1" /><br />
  4. <input type="checkbox" name ="jakis_check" value="T" /><br />
  5. <input type="submit" name="wyslij" value="wyslij" />
  6. </form>


  1. <? 
  2.  
  3. /* w uproszeczeniu podam tylko moje "zabezpieczenia" */
  4.  
  5. if ($_POST['wyslij'])
  6. {
  7. /* podstawowe zabezpieczenie */
  8. htmlspecialchars(strip_tags($_POST), ENT_QUOTES);
  9.  
  10. /* jak chcę mieć spokój z radio i checkboxami to buduję tablice dopuszczelnych wa
    rtości */
  11. $tabl3 = array('', 'P', 'Z', 'I');
  12. $valid = True;
  13.  if (!in_array($_POST['jakies_radio'], $tabl3)) { $valid = False; }
  14.  
  15. if ($valid != False)
  16. { 
  17.  do smth
  18. }
  19.  
  20.  /* jeśli mogę sobie na to pozwolić to sprawdzam URLa */
  21. if ($_SERVER['HTTP_REFERER']!= 'http://www.mojastrona/index.php5?name=formularz')
  22. {
  23. die ('bad idea');
  24. }
  25. else
  26. {
  27. wszystkie powyzsze zabezpieczenia
  28. }
  29. }
  30. else
  31. {
  32. $obj = new template_powyższego_htmla;
  33. }
  34. ?>


Ale wciąż mam wrażenie, że to za mało, albo zbyt toporne to to. Z różnych przyczyn nie bardzo mogę/chcę weryfikować wysyłany formularz generowanym hasłem w obrazku. Czy ktoś ma może takie "wzrocowy" przykład minimum zabezpieczeń dla formularzy?
sobstel
zabezpieczając się najpeirw należy się zastanowić przed czym się zabezpieczamy

1. po co htmlspecialchars(strip_tags( ? tego trzeba używać przy umieszczaniu danych w kodzie html (chyba ze na zapas), nie mowiac o tym ze w twoim przypadku jest to bledny zapis poniewaz zarowno strip_tags jak i htmlspecialchars nie moze przyjmowac jako argumentu tablicy. poza tym, przed sprawdzeniem poprawnosci danych nie powinno ich sie raczej zmieniac, uwazam ze walidacje powinno sie dokonywac na surowych danych takich jak dostarczono.

2. $_SERVER['HTTP_REFERER'] nie nawsze jest ustawiane,a moze tez sie roznic jak przechodzi przez rozne proxy. lepszym rozwiazaniem jest zastosoawnie jakiegos tokena (umieszczenie tokena w polu typu hidden i w sesji i potem sprawdzenie czy sie pokrywaja). btw, jest to zabezpieczenie przed proba bezposredniego wyslania danych z pominieciem wlasciwego formularza na stronie.

3. wszystko zalezy od przeznaczenia, jesli uwaznie przeczytales watek to byc moze zauwazyles ze nikt tutaj nie ma jednej skutecznej metody zabezpieczania. jesli umieszczasz dane w zapytaniach to trzeba np. uzyc mysql_real_escape_string, jesli dane wyswietlasz to htmlspecialchars, jesli chcesz sie zabezp przed xss to strip_tags [nawet bez tagow html da sie xss zastosowac, chociazby przez nieumiejetnie wykrozystany i napisany bbcode]. kombinacji i mozliwosc jest wiele, a bardzo duzo zalezy od specyfikacji danego problemu.
mumin.php
to może trochę sprecyzuję

Te zagrożone formularze na stronie wykorzystuję do przesyłania maili do konkretnego wskazanego odbiorcy w firmie. Jedne z formularzy to typowy formularz kontaktowy (imie, nazwisko, mail, twoja opinia), drugie to ankiety (dużo radiobuttonów, kilka textarea, kilka checkboxów)

Jakiś czas temu, ktoś zaczął podpinać się zewnetrznym formularzem i rozsyłać spamy - pakowali swoje nagłówki w maila i mieli pełną swobodę. Dlatego zastosowałem htmlspecialchars(strip_tags($_POST), ENT_QUOTES); - dało to taki efekt że przypinane zewnętrznie headers wyglądają mniej więcej tak:

Content-Type: text/plain; charset=\"us-ascii\"

więc już jest bezpieczniej,

$_SERVER['HTTP_REFERER'] =='url' powinno mnie chyba zabezpieczyć dość skutecznie przed podpinaniem się zewnętrznym formularzem pod mój?
sobstel
Cytat(mumin.php @ 30.05.2006, 10:26 ) *
$_SERVER['HTTP_REFERER'] =='url' powinno mnie chyba zabezpieczyć dość skutecznie przed podpinaniem się zewnętrznym formularzem pod mój?


Cytat("sopel")
$_SERVER['HTTP_REFERER'] nie nawsze jest ustawiane,a moze tez sie roznic jak przechodzi przez rozne proxy
mumin.php
Cytat(sopel @ 30.05.2006, 09:38 ) *
2. $_SERVER['HTTP_REFERER'] nie nawsze jest ustawiane,a moze tez sie roznic jak przechodzi przez rozne proxy.


Przyznaję, że niestety nie rozumiem tego wytłumaczenia sad.gif

jeśli url www.mojastrona.costam?name=formularz
wywołuje skrypt.php (wywoływany tylko if($_GET['name']=='formularz') ) w którym:
  1. <?php
  2. if(!$_POST['wyslij'])
  3. { 
  4. pokaż formularz 
  5. }
  6. else
  7. {
  8. if ($_SERVER['HTTP_REFERER'] !='www.mojastrona.costam?name=formularz')
  9. {
  10. die ('nie rob nic');
  11. }
  12. else
  13. {
  14.  wyslij formularz
  15. }
  16. }
  17. ?>


to jak to można obejść?

jeśli pytanie jest bardzo lamerskie to już więcej nie będę męczył
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-2024 Invision Power Services, Inc.