ugrás a tartalomhoz

Kezdő bakik: web 1x1

janoszen · 2010. Szep. 25. (Szo), 08.46

A fórumon többször kerülnek elő olyan kérdések, amelyeknek véleményem szerint nem szabadna előkerülniük, ha lenne egy jó leírás arról, hogyan is működik a web. Annak idején én Stefan Münz SelfHTML-jéből tanultam, ami nagyon alapos és módszeres magyarázattal vezeti be a tanulni vágyót a webfejlesztés világába. Egyetlen hibája van: csak németül érhető el. Ugyan ennyire részletes leírásra nem vállalkozhatom, de ezúttal megpróbálom összeszedni a leggyakrabban elkövetett kezdő bakikat.

A haladóbb felhasználók kedvéért elmondom, hogy az itt leírt probléma felvetések nem a teljesség igényével készültek, sok helyen nem írom le a kevésbé triviális példákat. A cél itt az, hogy a kezdők el tudják kerülni a legnagyobb aknákat.

Szerver oldal vs. kliens oldal

Az első, a fórumokon általában erős intoleranciát kiváltó probléma az szokott lenni, ha a kérdező nincs tisztában azzal, mi hol fut. Nézzük meg tehát, hogyan is történik egy weboldal kiszolgálása.

  • Beütjük a böngészőnkbe, hogy example.com.
  • A böngésző az operációs rendszer segítségével megnézi a domain név milyen IP címhez tartozik.
  • A böngésző megnyit egy kapcsolatot a szerver felé (IP cím szerint, itt már nincs domain) és lekéri a kezdőlapot. (Ez a / cím.)
  • A szerver megnézi, hogy a kezdőlapra milyen fájlt kell visszaadni (index.html, index.php stb.).
  • Ha a fájl valamilyen szerver oldali programozási nyelvben készült (PHP, Perl, Python), a szerver lefuttatja a programot. A program futásának az eredményét adja oda a böngészőnek. (Ergó nem, hacsak nincs hiba a szerver oldali kódban, nem tudod megnézni a forrást!)
  • A böngésző a kapott fájlt (pl. HTML) megjeleníti és betölti a hozzá szükséges képeket, egyéb fájlokat illetve elkezdi futtatni a kliens oldali scripteket (pl. JavaScript).
  • Ha a felhasználó linkre kattint, vagy mondjuk a JavaScript új adatot kér le, a böngésző új lekérdezést indít.

Mint látható, ez egy oda-vissza adogató játék. Ennek az egyik legfontosabb következménye, hogy nem lehet a JavaScript és a PHP között közvetlenül adatokat átadni, ahhoz új lekérdezést kell intézni a szerverhez.

Munkamenet kezelés

A fentiekből következik, hogy két lekérdezés között nincs olyan adat, ami megmaradna. Ahhoz, hogy adatot tudjunk átadni, munkameneteket kell használnunk. Erről itt a Weblaboron is született már cikk.

A különbség a GET és a POST között

Sokszor képzavar van a GET és POST kérések között, leggyakrabban az űrlapokkal kapcsolatban. Egyszerűen mondva: a GET kérések paraméterei látszanak a címsorban, a POST kéréseké nem. Bónuszként csak POST-tal lehet fájlt feltölteni. Néhány alapszabály:

  • Keresést és hasonló dolgokat mindig GET-tel intézünk, hogy lehessen bookmarkolni.
  • Módosító, törlő lekérdezéseket kizárólag POST-tal intézünk, különben valakinek küldök egy linket és ha be van lépve, letörli a cikkét. (Ha valaki kekeckedne: előbb átküldöm egy URL rövidítőn keresztül, és akkor biztos megeszi az ismerős.)
  • Ez utóbbi esetben kötelező ellenőrizni a szerver oldalon, hogy tényleg POST kérés jött. ($_REQUEST-ből olvasni = nem menő).

Működési logika és a kiírás szeparálása

A legtöbb kezdő örül, ha sikerül valahogy összekalapálni a programot, nem igazán gondol a kódszervezésre, viszont a hibakeresésnél létfontosságú lehet. Mit értek ez alatt? Ha például adatot kérünk le adatbázisból, először gyűjtsük össze egy tömbbe, majd utána külön irassuk ki. Ezáltal a kettő között a hibakeresés idejére ki tudjuk iradni az adatot és nem kell nézegetni, hogy vajon a HTML-ben van a hiba, vagy a PHP kódban, ezzel felezve a kódmennyiséget, amiben hiba lehet. Például:

$r = mysql_query("SELECT * FROM comments WHERE topic_id=5");
$comments = array();
while ($a = mysql_fetch_assoc($r)) {
	$comments[] = $a;
}
/* Itt irhatjuk ki hibakereses eseten
a tombot, pl igy: var_dump($comments); */
foreach ($comments as $comment) {
	echo("Név: " . $comment['name'] . "\n");
	echo("Hozzászólás: " . $comment['comment'] . "\n\n");
}

Mennyivel tisztább így. :)

Escape-elés, bemeneti adatok ellenőrzése

Hasonlóan az előzőhöz, a kezdő örül, ha működik, nem igazán gondol a biztonságra. Nézzük a következő kódot:

mysql_query("SELECT COUNT(*) FROM users WHERE username='" . $_POST['user'] . "' AND password='" . $_POST['pass'] . "'");

Mi történik vajon, ha én most azt írom be a password paraméterbe, hogy:

' OR '1'='1

Ez esetben a lekérdezés így fog kinézni:

SELECT COUNT(*) FROM users WHERE username='admin' AND password='' OR '1'='1'

Mi történik? Be tudok lépni adminként, noha nem is volt meg a jelszavam. (A működése szerver beállítástól függhet, de az elvet jól demonstrálja.) Ez esetben a bemeneti adatok ellenőrzésének hiánya egy úgy nevezett SQL injection sebezhetőséghez vezetett. Ennél még sokkal rosszabb is lehett volna, a támadó a nevünkben lefuttathatott volna egy DROP DATABASE parancsot is. Nézzük a leggyakrabban elkövetett sebezhetőségeket és a védelmi lehetőségeket:

SQL injection

Az SQL injection, mint a fenti demonstráció is mutatja, egy SQL parancs beszúrását jelenti. Ellene úgy kell védekezni, hogy az általunk használt adatbázis kezelő réteg escape függvényét használjuk. PHP MySQL extension esetén ez a mysql_real_escape_string(). A fenti query tehát helyesen:

mysql_query("SELECT COUNT(*) FROM users WHERE username='" . mysql_real_escape_string($_POST['user']) . "' AND password='" . mysql_real_escape_string($_POST['pass']) . "'");

Figyelem! Senkinek még véletlenül se jusson eszébe, hogy saját szűrő függvényt ír! Az adatbázis rétegek és implementációk változhatnak, valamint közre játszhat a felhasznált karakterkódolás is, így ezek ismerete nélkül szinte lehetetlen jó védelmet írni!

HTML injection, XSS

Ha a felhasználó bemenetet bárhol ki is írjuk (enélkül viszonylag céltalan a dolog), akkor védekeznünk kell a HTML injection és az XSS ellen is. Egy részről azért, hogy ne tudja bárki tetszőleges HTML-lel szétbarmolni az oldalt, másrészt hogy ne tudjon olyan JavaScriptet beszúrni, ami alkalmas a felhasználó belépési adatainak az ellopására. Ha semmilyen HTML-t nem szeretnénk megengedni, akkor PHP esetén elég a htmlspecialchars() használata.

Ha JavaScriptnek szeretnénk átadni adatot, akkor azt a json_encode() hívással kell escape-elni.

Tanács: az ilyen escape-elést a kiíráskor végezzük, ne az adatok mentésekor. Így ha esetleg módosításokra van szükség a szűrő algoritmuson, nem kell újra konvertálnunk a már meglevő adatokat. Ezen felül ha változtatunk a kimeneti formátumon (például HTML helyett JSON-t küldünk), akkor igen csak nagy gondban lehetünk.

URL injection

Ha a felhasználó által adott értékeket linkbe írjuk, ki kell védenünk azt, hogy tetszőleges GET paramétert tudjon manipulálni az által, hogy beír egy kérdőjelet vagy egyenlőség jelet. Az ilyen irányú védelemre az urlencode() függvényt kell használni. Például így:

echo('<a href="/kereses?q=' . urlencode($elozokereses) '">előző keresés</a>');

CSRF

A CSRF jóval trükkösebb jószág. Legegyszerűbb példaként azt lehetne fölhozni, hogy valaki egy idegen oldalon csinál egy láthatatlan űrlapot, ami a mi oldalunkra küldődik el. Ha a felhasználó be van lépve mondjuk az admin oldalra, azt is elérheti a preparált oldal, hogy töröljük valamelyik cikkünket. Védekezni ez ellen nem egyszerű, a munkamenetünkbe be kell helyeznünk egy munkamenetenként egyedi változót (cannary), amit a formok elküldésekor ellenőrzünk. Ha nem stimmel, hibát írunk ki. Mivel a felhasználónak kiosztott cannaryhoz a másik oldal nem fér hozzá, ezért nem fogja tudni elküldeni a formot.

URL manipulation

Ha valamilyen paraméterek vannak az URL-ben, akkor nézzük meg, mi történik, ha manipuláljuk őket. Ha nem ellenőrizzük őket, könnyen lehet, hogy a felhasználó hozzá tud férni olyan dolgokhoz, amikhez nem kellene neki. Soha, de soha ne feltételezzük, hogy a felhasználó nem tudja, mit kell beírni a címsorba! A gyakorlat azt mutatja, hogy de, tudja. Megtalálja.

Remote code execution

Ez minden sebezhetőség lerondábbika. Hál' istennek nem gyakran fordul elő, de ha előfordul, akkor a támadó a szó legszorosabb értelmében bármit megtehet a weboldalunkon.

Leginkább akkor vagyunk veszélyben, ha a felhasználó által feltöltött adatot fájlba tesszük, majd include vagy require paranccsal olvassuk fel, illetve ha a rendszerünkben shell (shell_exec(), exec stb.) vagy eval() hívások vannak.

A védekezés egyszerű: ne használjunk ilyen hívásokat. Az esetek 99%-ában ezekre semmi szükség, pusztán a programozó volt lusta rendesen megírni a kódot.

Gyakorlati példa: Az egyik ilyen díszpinty az e107 rendszer volt, ahol a contact.php-ba szültek egy sebezhetőséget, aminek következtében a támadó a rendszeren elindíthatott egy programot a háttérben, ami elkezdte önmagát tovább terjeszteni és a helyi szervert zúzni. Hogy hogy sikerült ezt elkövetniük, foglamam sincs, de úgy általában jellemzi az e107 biztonságát és úgy általában kezet foghat a PHPFusion nevű haverjával. Persze szigorúan a személyes magánvéleményem szerint.

Karakterkódolás

Amin szinte minden kezdő elvérzik, ha nem előbb, akkor utóbb egy oldal költöztetésnél, az a karakterkódolás. Ez azért problémás, mert ha egyszer rosszul van bent az adatbázisban az adat, közel lehetetlen helyre rakni, főleg a szolgáltatás teljes leállítása nélkül

Az átlag weboldalnak három pontja van, ahol el lehet ezzel csúszni:

  • A böngésző. A HTML karakterkódolását a Content-Type HTTP fejlécben vagy <meta> tagben tudjuk megadni. Az előbbi erősebb, mint az utóbbi, tehát ha a szerver gazdája beállított valamit, akkor a <meta> nem segít.
  • A MySQL kapcsolat. Akármilyen furán hangzik, a MySQL kapcsolat és az eltárolt adat karakterkódolása nem feltétlenül azonos. A szerver automatikusan konvertál. Ha ezt nem jól állítjuk be, akkor az adatbázisban az ő szemszögéből értelmezhetetlen bináris szemét lesz, ami exportáláskor arcon is csapja az ember amolyan péklapát-stílusban.
  • A MySQL adatbázis. Ha a táblák karakterkódolását nem jól állítjuk be, könnyen lehet, hogy a magyar ékezetes karaktereink elvesznek.

Best practice elven javaslom, hogy mindhárom karakterkódolás legyen azonos! Ha valahol inkonzisztencia lép fel, végeláthatatlan karakterkonverziós szívások lépnek fel! Mivel ma már minden weben haszált program támogatja az UTF-8-at, érdemes azt használni.

Gyorstalpaló a megfelelő lépések betartására:

  • PHP-ból küldjük ki a megfelelő fejléceket: header("Content-Type: text/html; charset=UTF-8");
  • A MySQL-hez való kapcsolódás után állítsuk be a kapcsolat karakterkódolását: mysql_query("SET NAMES utf8");
  • MySQL tábla létrehozáskor biggyesszük oda a karakterkódolást: CREATE TABLE t1 (…) CHARACTER SET utf8 COLLATE utf8_general_ci;

Fórum tippek

Ha a fórumban kérdezel (nem csak itt, máshol is), érdemes úgy megszerkeszteni a kérdést, hogy a közösség az értelmezés helyett a probléma megoldására fordíthassa az agykapacitását. Erről külön blogbejegyzésben értekezem.

 
1

Nemzeti alaptanterv

ern0 · 2010. Szep. 25. (Szo), 11.07
Majd csináljatok egy rövid címlap jellegű oldalat ezeknek a cikkeknek, hogy ne vesszen el a blogposztok folyamában.
2

Jó post, várjuk a többit.

demo · 2010. Szep. 25. (Szo), 14.12
A karakterkódoláshoz még egy dolog. Maga a fájl kódolása sem mindegy.
3

Ez lesz az a bejegyzés a

inf · 2010. Szep. 25. (Szo), 14.52
Ez lesz az a bejegyzés a weblaboron, amire a legtöbb külső link fog mutatni. :-)
Már nagyon-nagyon régen meg kellett volna írni, mert az esetek 95%-ában ilyeneket kérdeznek a fórumokon. Szép munka! :-)


Szerintem létre lehetne hozni valami FAQ vagy kezdőknek vagy hasonló menüpontot, ahova az ilyenek bekerülnének. Szerintem van még néhány téma, ami ide tartozna, pl: egy webszerver telepítése, vagy svn telepítése és használata, és még sorolhatnám...
4

Szép munka, remélem lesz

csaba86 · 2010. Szep. 25. (Szo), 14.53
Szép munka, remélem lesz folytatása is (egészen a profi szintig :D). Szerintem ezentúl is fognak ilyeneket kérdezni, de réméljük kevesebb alkalommal.

Számomra nagyon hasznos volt az írás, nagyon jó kis összefoglaló volt.
6

Wiki volt

Török Gábor · 2010. Szep. 25. (Szo), 16.13
Szerintem létre lehetne hozni valami FAQ vagy kezdőknek vagy hasonló menüpontot, ahova az ilyenek bekerülnének.

Anno pont proclub vezényletével indult meg a Weblabor Wiki projekt, ami kellő támogatás nélkül elapadt, ha jól tudom. Ha a jövőben proclub és mások tollából megindul az ilyen irányú cikkek publikálása a WL-en, akkor valóban lehet értelme majd egy FAQ rovatba sorolni őket.
7

Hát erről a wikiről nem

inf · 2010. Szep. 25. (Szo), 16.44
Hát erről a wikiről nem tudtam, azt hiszem akkor még nem sűrűn néztem az oldalt.

(Mindenestre ha lesz a későbbiekben kezdőknek szóló rovat, akkor légyszi ne FAQ legyen a neve, mert elég csúnya egy angol rövidítés egy magyar nyelvű menüben.)
5

Hmm azt hiszem a későbbiekben

inf · 2010. Szep. 25. (Szo), 14.59
Hmm azt hiszem a későbbiekben írok valamit arról, hogy hogyan kell debuggolni, mert szerintem az a baj legtöbbször, hogy nem is próbálkoznak meg vele, hanem egyből fórumra futnak, hogy "mi lehet a hiba" meg "nem működik" ...
8

és valahogy minden kifért

barii · 2010. Szep. 25. (Szo), 18.07
és valahogy minden kifért ide, egy bejegyzésbe, ami a pár bejegyzéssel ezelőtti Biztonságos PHP könyvben el van húzva fejezeteken át.
9

Nagyszerű hogy leírtad

nevemrock · 2010. Szep. 25. (Szo), 18.12
Nagyszerű hogy leírtad, az igazán jó az volna ha tényleg tanulnának belőle az emberek.

2010-et írunk, de 'programozók' olyan kódokat csinálnak, hogy pillanatok alatt kifekteted. (ez már 5 évvel ezelőtt is gáz volt.)

Már sokszor beszéltem kezdőknek a fentiekről, de egyszerűbb gagyi kódot írni és _REQUEST tömböt piszkálni (messziről, bottal). Mint néhány alapszabályt betartani és a biztonság lebegjen a szem előtt.
10

ez biztos?

Edit · 2010. Szep. 25. (Szo), 23.43
A böngésző az operációs rendszer segítségével megnézi a domain név milyen IP címhez tartozik.


Hát végül is lehet mondani, egy számítógépen majdnem minden az operációs rendszer segítségével történik. :)
11

pár fontos apróság

prom3theus · 2010. Szep. 26. (V), 10.15
Nagyon jónak találom (bár ezt a kezdők majd hasznosság alapján jobban eldöntik :)), proclub cikkei tátongó réseket tömnek ki mostanság hétről hétre - minden elismerésem!

Lenne viszont pár észrevételem (elnézést, ha olyan is van, amit előttem már leírt valaki).

Szerver oldal vs. kliens oldal:
A böngésző megnyit egy kapcsolatot a szerver felé (IP cím szerint, itt már nincs domain) és lekéri a kezdőlapot. (Ez a / cím.)

Itt én talán kivenném a zárójelet. Ugyan szigorú értelemben valóban nincs már név feloldás, azonban a HTTP lekérésben eljut a szerverhez a domén neve, és a kiszolgáló fel is dolgozza azt. Nem ártana megemlíteni szerintem (linkelni) hogy a kérések a HTTP protokolon keresztül zajlanak, aminek pontos leírása elérhető, ez a leírás a 2616-os RFC. Az, hogy valaki kezdő, nem jelenti, hogy nem fogja legalább átfutva megpróbálni megérteni (sőt, tapasztalatom, hogy nagyon sok középhaladónak sincs arról halovány gőze, hogy valójában hogyan működik ez a kliens-szerver kapcsolat, és mit miért úgy kell ahogyan).

A különbség a GET és a POST között:
Itt talán a legfontosabb különbség hiányzott: a GET lekérés hossza korlátos (böngészőtől függő, de néhány száz karakter), míg a POST-é nem. Ez magyarázza a többi pontot is.
Azt, hogy a kérés GET volt-e vagy POST ellenőrizni felesleges. Ez egy félreértés: a POST lekérés semmivel sem különlegesebb (vagy nem sokkal), mint a GET, telnet kliensben egy sima POST lekérést megírni ugyanannyi, mint egy GET-et. Vagy ha valaki idáig nem süllyed, CSRF-fel még mindig simán átverheti a szervert. Tehát sokkal célszerűbbnek tartok minden mást vizsgálni, mint ezt, mivel könnyen hamisítható. És itt mondjuk utalnék is a szépen összeszedett biztonsági problémákra. Tulajdonképp még senki nem tudott nekem meggyőző érvet mondani arra, hogy miért jó ellenőrizni a lekérés típusát biztonsági célból.
A kárhoztatott $_REQUEST változó használatával pedig csak annyi probléma van (és EZT érdemes ellenőrizni viszont), hogy ha egy űrlap POST-ként kerül elküldésre, de a request URI-ben (ez a <form> tag action paraméterének értéke) is szerepelnek paraméterek, akkor a PHP a request URI-ből vett paramétereket a $_GET tömbbe fogja tenni, a POST-ban szereplő (az űrlap mezőitől kapott) értékeket a $_POST-ba, DE ha a $_GET-ben és a $_POST-ban szerepel azonos nevű paraméter különböző értékkel, akkor a $_REQUEST-ben csak a POST érték fog szerepelni! Az ilyen esetek viszont kis odafigyeléssel elkerülhetőek, ha az űrlapok kialakításánál ügyelünk arra, hogy az action paraméterben ne szerepeljen a lekérésben olyan paraméter, amit név szerint megkap a szerver egy űrlapmezőtől is!

Példakód (csúf, de hasznos, nem valid :-P):
<form method="POST" action="/tries/formmethod.php?x=1&amp;y=2"><input type="hidden" name="y" value="3">z:<input type="text" name="z"><input type="submit" name="submit"></form>
<?php

echo "SERVER:<br>";
var_dump($_SERVER);
echo "<br>GET:<br>";
var_dump($_GET);
echo "<br>POST:<br>";
var_dump($_POST);
echo "<br>REQUEST:<br>";
var_dump($_REQUEST);

?>
Működési logika és a kiírás szeparálása:
Ebben a fejezetben ha már szó esik az adatbázis kezelésről, már csak népnevelő célzattal is megérdemelt volna szerintem egy linket a PDO is, hátha vannak olyan kezdő webfejlesztők, akik korábban már találkoztak valamilyen objektum-orientált nyelvvel. A PDO használatához egyébként még annyira nagy OO ismeret sem szükséges, lényegesen egyszerűbb sok szempontból mint a xyz_query() és társai, tekintve hogy szabványos a felülete, azaz független az adatbázis elérő rétegtől (például az említett escape-elés is, amit egyébként PREPARE lekérés esetén a PDO automatikusan megcsinál).

Karakterkódolás:
A három pont valójában négy! A munkafájlok (php kód, HTML sablonok, JS-ek, stb) mind UTF-8 kódolásúak kell hogy legyenek egységesen, különben ez a fejezet semmit se fog érni, hibásan enkódolt karakterek (ő, ű feltétlen) továbbra is meg fognak jelenni, ha azok fájlban szerepelnek (pl. űrlapmező előtti címkeként a sablonban)!

Biztonsági kérdésekhez:
Lehet, hogy a hivatkozott cikk a munkafolyamatokról kifejti, de az injection-ök és egyéb hasonszőrűek közt csak az említés szintjén (esetleg újra hivatkozva) megemlíteném a session biztonsági problémákat is, azaz hogy a munkafolyamatokkal illetéktelenek - a megfelelő ellenőrzések elvégzése hiányában - könnyen visszaélhetnek egy belépett felhasználó jogosultságaival. A munkafolyamat ellopható!
Ugyanitt elmondanám azt is, hogy a CSRF-ek védhetőek a munkafolyamatok bevezetésével (és a felhasználó $_SESSION változóban való azonosításával), ugyanis ha az ellopott űrlaphoz nem tartozik munkafolyamat, akkor nem futtatható egy belépett felhasználó nevében. Egyébként ugyanitt linkelném ezt is: Munkamenet kezelés biztonsági kérdései

És bocsánat, hogy ennyi haladó szottyot írtam, de úgy gondoltam, ha netán egyik-másik észrevételem alapján visszamódosításra kerül a bejegyzés, akkor ahhoz a szakmai érvek nem ártanak, a bejegyzés nyelvezete viszont maradhat az, ami volt (én ennyire fogyasztható módon nem tudok fogalmazni, ezt az íróra bíznám, mert neki jól láthatóan megy).
12

GET - POST ellenőrizés

solkprog · 2010. Szep. 26. (V), 10.32
Azt, hogy a kérés GET volt-e vagy POST ellenőrizni felesleges...
...Tulajdonképp még senki nem tudott nekem meggyőző érvet mondani arra, hogy miért jó ellenőrizni a lekérés típusát biztonsági célból.

cikkből idézve:
Módosító, törlő lekérdezéseket kizárólag POST-tal intézünk, különben valakinek küldök egy linket és ha be van lépve, letörli a cikkét. (Ha valaki kekeckedne: előbb átküldöm egy URL rövidítőn keresztül, és akkor biztos megeszi az ismerős.)
18

CSRF tamadas POST-ot is

Tyrael · 2010. Szep. 26. (V), 21.50
CSRF tamadas POST-ot is ugyanugy at tud vagni (megnezed az en artalmas weboldalamat, ami js segitsegevel postol egy iframe-be, ergo a te nevedben vegez modosito lekerdezest, tehat nem elegseges vedelem a CSRF ellen a get helyett post megkovetelese)

a post vs get inkabb a szemantikus web, illetve usability miatt fontos.
post-olt oldalt nem tudok egyszeruen bookmarkolni, share-elni, illetve ha mar van HEAD, GET, PUT, POST, DELETE az RFC-ben, akkor erdemes lehet hasznalni, es ezaltal utalni a method-dal, hogy mi tortenik a hatterben (ugyanitt erdemes lehet a response kodokat megemliteni).

tehat szerintem tisztan security szempontbol nem jobb egyik, mint a masik.

Tyrael
20

Valamint ha egy GET

tgr · 2010. Szep. 27. (H), 17.48
Valamint ha egy GET linket/formot teszel ki, azzal azt állítod, hogy a kérésnek nincs mellékhatása (és némelyik keresőrobot vidáman el is küldi, illetve link esetében akár egy nemstandard prefetching beállításokat használó böngésző is).
21

ez nem biztonsagi szempont,

Tyrael · 2010. Szep. 27. (H), 21.37
ez nem biztonsagi szempont, hanem szemantikai.

amugy egyik haverom jart ugy, hogy sehol nem publikalt weblap publicbol elerheto, de sehol nem linkelt cronjobjat kezdte el hivogatni valami (mondtam hogy ne ugy csinalja, hosszu tortenet), mire kideritettuk, hogy fent volt nala az alexa toolbar, ami hazakuldte hogy milyen url-eket nezett meg a bongeszobol, majd ezeket az alexa crawler-e megprobalta felindexelni...
szoval ilyen is van

Tyrael
25

nagyságrend

solkprog · 2010. Szep. 29. (Sze), 09.58
azért a get könnyebb:
Szomszéd pistike miután szakított a barátnőjével küldöd neki egy olyan linket amire ha rákattintva a volt barátnő akaratlanul töröli az összes levelét. (wwww.emailszolgaltato.hu/mail?action=mailDeleteAll)
Jó oké ezt post-al is meglehet játszani, de azért get-el egy nagyságrenddel könnyebb.

(használd egészséggel, de én nem biztonsági szempontból nem tanácsolnám hosszú távon)
26

manapsag ugye a csrf

Tyrael · 2010. Szep. 29. (Sze), 10.15
manapsag ugye a csrf tamadasos linkek tobbnyire mind url roviditon/obfuscalon vannak keresztul tolva.
onnan pedig mar mind1, hogy direktbe a mailDeleteAll az getet vagy postot var egeszen addig amig van js a kliens bongeszojeben (ami manapsag majd mindenutt van).
ha post kell, akkor a href.hu-s link a tamado sajat oldalara fog dobni, ami js-bol eltolja a postot.
sot ha nagyon otletesek akarunk lenni, akkor akar egy A site XSS sebezhetoseget is ki tudjuk hasznalni ugropontnak a B site-ra valo CSRF-hez, igy meg sajat tarhelyet sem kell regisztralnunk/fenttartanunk, vagy hasznalhatunk akar egy http://jsbin.com -hoz hasonlo szolgaltatast is.

Tyrael
27

értelek ám

solkprog · 2010. Szep. 29. (Sze), 10.36
Én ezt mind tudom hidd el.

Viszont akkor közelítsük meg máshonnan a témát: ha valaki "fel akarja törni" az oldalad, biztos lehetsz benne hogy az elsők között lesz az hogy megnézi hogy használják-e a $_GET[], $_POST[]-ot, mert általában a $_REQUEST[]-őt a kezdők használják, és ennek következtében jó esélyel feltörhető az oldal, ergó érdemes küzdeni vele.
28

Én ezt mind tudom hidd

Tyrael · 2010. Szep. 29. (Sze), 11.49
Én ezt mind tudom hidd el.

nem voltam biztos benne a hozzaszolasod alapjan

Viszont akkor közelítsük meg máshonnan a témát: ha valaki "fel akarja törni" az oldalad, biztos lehetsz benne hogy az elsők között lesz az hogy megnézi hogy használják-e a $_GET[], $_POST[]-ot, mert általában a $_REQUEST[]-őt a kezdők használják, és ennek következtében jó esélyel feltörhető az oldal, ergó érdemes küzdeni vele.

ha valaki fel akarja torni a site-odat, akkor elso korben fog nyomni par blind code/sql injectiont, ha ezek nem jonnek be, akkor csinal egy alaposabb terkepet a rendszerrol (portscan, szolgaltatasok verzioinak megszerzese, a webalkalmazás belépési pontjainak feltérképezése, social engineering, etc.) ez alapján pedig elkezdi módszeresen végigpróbálgatni azokat a sebezhetőségeket, amik a legkevesebb munkával, a legtöbb eredményt igérik.

Nem azért lesz sebezhető a REQUEST sem, mert a Cookie felülcsaphatja a POST-ban tárolt azonos nevű változót vagy fordítva a $_REQUEST tömbben, hanem mert nem megfelelően vannak validálva a klienstől érkező adatok.

Számomra a post, vagy cookie változók ugyanolyan "gyanúsak" mint a getben kapottak.
Innentől kezdve az én kódom nem lesz kevésbé biztonságos ha a $_POST helyett a requestet használom, a legroszabb ami történhet, hogy van 2 azonos nevü, de eltérő funkcióju változom(ami már eleve gáz megoldás) amik a ráadásul egy funkción belül szükségesek (tehát van egy oldalam, amit post-tal várok, de az url-ből is használom az azonos nevű get parametert => megatakony), es ebben az esetben az a funkcio nem vagy nem megfeleloen fog mukodni (de a szabalytalan mukodes nem lehet biztonsagi problema, hiszen a klienstol erkezo adatok validalva vannak).

persze ez csak az en velemenyem, de szerintem maga a REQUEST nem biztonsagi tenyezo, esetleg ahogy te is mondtad, gyakran jarhat egyutt a REQUEST hasznalata mas problemakkal is, de ez nem ok-okozati osszefugges szerintem.

viszont sikerult elerni vele, hogy egy amugy artalmatlan eszkoz ki lett kialtva egbekiallto biztonsagi problemanak.

ps:
az ilyen "általában" általánosításokkal jól lehet érvelni egy vitában, de általában kiderül, hogy nem a valóságot, hanem az általánosító ember szűk környezetét tükrözik.

Tyrael
29

re

solkprog · 2010. Szep. 29. (Sze), 14.16
Én ezt mind tudom hidd el.
nem voltam biztos benne a hozzaszolasod alapjan

-szerintem hülyességet nemírtam...

hozzászólásod középső részére nem reagálnék mert totál egyetértek/igazat írtál.

gyakran jarhat egyutt a REQUEST hasznalata mas problemakkal is, de ez nem ok-okozati osszefugges szerintem.
-erre akkartam célozni (ezekszerint túl röviden írtam)

az ilyen "általában" általánosításokkal jól lehet érvelni egy vitában, de általában kiderül, hogy nem a valóságot, hanem az általánosító ember szűk környezetét tükrözik.
-meglehet. Akkor átfogalmazom: tapasztalatom szerint aki a REQUEST-et használja az nagy valószínüséggel kezdő. De örülök hogy te a nem ilyen kódokkal találkozol.

off: én azért nem használom a REQUEST[]-őt mert szeretem látni hogy az a változó honnan jött. (ha fél év után kell ránézzek a kódra akkor meg pláne)
13

DE ha a $_GET-ben és a

Poetro · 2010. Szep. 26. (V), 12.41
DE ha a $_GET-ben és a $_POST-ban szerepel azonos nevű paraméter különböző értékkel, akkor a $_REQUEST-ben csak a POST érték fog szerepelni!

Ez így ebben a formában nem igaz, ugyanis ez a variables_order PHP beállítástól függ, habár alapértelmezésben ez EGPCS. Azaz a POST változók felül fogják írni a GET változókat, DE a COOKIE változók is felül fogják ezeket írni, amit meg ugye szintén könnyű hamisítani, ezért a $_REQUEST használata messze kerülendő, kivéve, ha nagyon tudjuk, mit csinálunk.
14

CSRF, SESSION

erenon · 2010. Szep. 26. (V), 13.41
Ugyanitt elmondanám azt is, hogy a CSRF-ek védhetőek a munkafolyamatok bevezetésével (és a felhasználó $_SESSION változóban való azonosításával), ugyanis ha az ellopott űrlaphoz nem tartozik munkafolyamat, akkor nem futtatható egy belépett felhasználó nevébe


Ez így nem pontos. A CSRF lényege, hogy az áldozat maga küldi el a kérést. Egy megoldás lehet, hogy az űrlapban küldünk egy plusz azonosítót is, amit tárolunk a munkamenetben is.

Továbbá, mint előttem írták, a POST "biztonságosabb" CSRF tekintetében, mint a GET, ugyanis (AFAIK) nem tudsz olyan linket elküldeni az áldozatnak, ami POST kérést hajtana végre.
15

Ez így nem pontos. A CSRF

inf · 2010. Szep. 26. (V), 16.00
Ez így nem pontos. A CSRF lényege, hogy az áldozat maga küldi el a kérést.
Nem az áldozat, hanem a támadó domain küldi a kérést az áldozat böngészőjén keresztül úgy, hogy az áldozat erről semmit nem tud.

Ettől függetlenül a munkafolyamat csak nagyon gyenge védelmet ad, hiszen munkafolyamatot is lehet indíttatni CSRF-el ugyanúgy, mint bármilyen más kérést.
19

ez sajna nem

Tyrael · 2010. Szep. 26. (V), 21.51
ez sajna nem igaz.
http://www.cgisecurity.com/csrf-faq.html#post

Tyrael
16

Wiki

gphilip · 2010. Szep. 26. (V), 18.19
Nagyon jól látszik ebben a bejegyzésben, hogy egy wiki mennyit segítene, hiszen mindenki hozzátette a saját kis pontosítását és extra információit, amit fontosnak gondolt.

Részemről:
- a GET és a POST közötti különbséget nagyon jól leírna a nevük - a GET-tel kérünk valamit (tartalmat), a POST-tal küldünk (formot, valamiféle utasítást)
- a CSRF-re alapvető védelmet nyújt a tokenek használata

Továbbá nem láttam és nagyon fontos:

Ha felhasználók adatait rögzítjük, a lehető legóvatosabban kell eljárnunk. a jelszó mindenképpen hash-elve (salting!) legyen eltárolva - hash =/= encyption! Nagy méretű adatbázis esetén a felhasználók e-mail címét és személyes adatait tároljuk valamilyen titkosító algoritmussal.

Azt kell feltételeznünk, hogy az adatbázishoz bárki hozzáfér.

Mellesleg 1x1 témáan nekem referencia:
http://stackoverflow.com/questions/72394/what-should-a-developer-know-before-building-a-public-web-site
17

Köszönöm

janoszen · 2010. Szep. 26. (V), 19.30
Kedves hozzászólók!

Köszönöm a rengeteg hasznos hozzászólást és elnézéseteket kérem, hogy csak most reagálok, de külföldön voltam, amikor kikerült az írás.

Az egyetlen dolog, amit javítandónak érzek, az a fájl karakterkódolása és a BOM karakterek, ezt korrigálni fogom, amint gép elé jutok. A többi témában engedelmetekkel a kommentjeiteket hagynám itt pontosítás, kiegészítés gyanánt.

Ami a wikit illeti, nagyon kiesett a Weblabor vérkeringéséből, ezért egy idő után elhalt. Azt javaslom, egy külön tartalmi rendszer helyett csináljunk egy sitemap-szerű indexet a cikkekről a már meglevő tagek alapján. Ha valaki ért a Drupal fejlesztéshez és van szabadideje, alkothatna egy ilyet.

További kellemes hétvégét:

János
22

$_request miért ne?

Librama · 2010. Szep. 28. (K), 14.31
Sziasztok!

Kezdőként olyan nagyon nem derült ki világosan számomra, hogy a $_request használata miért nem támogatott.. (Mikor elég sok PHP oktatókönyv ennek használatát okítja)

Felhomályosítana valaki?


Köszönöm
23

Lásd korábban

Poetro · 2010. Szep. 28. (K), 14.50
A 13. hozzászólásban szerintem elég jól részleteztem mi a probléma a $_REQUEST-tel.
Idézetek az oldalról:
An associative array that by default contains the contents of $_GET, $_POST and $_COOKIE.

The variables in $_REQUEST are provided to the script via the GET, POST, and COOKIE input mechanisms and therefore could be modified by the remote user and cannot be trusted. The presence and order of variables listed in this array is defined according to the PHP variables_order configuration directive.
24

Honnan jött?

janoszen · 2010. Szep. 28. (K), 18.58
Konyhanyelven megmagyarázva Poetro válaszát: nem tudod, hogy az adott értéket GET vagy POST metódusban passzolták át, esetleg sütiből jött-e. Természetesen mind a felhasználótól jön, de az írásban kifejtettem, miért nem mindegy, hogy GET vagy POST.
30

Szóval ne használjunk

Librama · 2010. Szep. 29. (Sze), 14.46
Szóval ne használjunk $_requestet - OK.
Szűrjük a bemenő adatokat - OK.
ahogy kihámozom a szövegből a 'cookie változók' felülírják a GET és POST adatokat is - OK.

Akkormárcsak azt kérdezném - kezdőként, "...aki örül ha összekalapál egy működő kódot"
hogy amolyan "..best practice"-ként $request helyett MIT és HOGYAN ajánlott használni?
31

Re: Szóval ne használjunk

Max Logan · 2010. Szep. 29. (Sze), 15.01
$_REQUEST helyett $_GET, $_POST, $_COOKIE és ha kell, akkor a $_SERVER.

A COOKIE-k pedig nem feltétlenül írják felül a többit, lásd: php.net vonatkozó írását, melyet már valaki korábban linket.

Egyébként én életemben nem használtam a $_REQUEST tömböt ...
32

apró megjegyzés

solkprog · 2010. Szep. 29. (Sze), 17.45
Szűrjük a bemenő adatokat

kicsit pontosabban: Felhasználótól érkező minden adatot szűrjünk! (pl. $_SERVER tömb értékeit szeretik elfejteni)
33

Karakterkódolás string függvényeknél

Fodi69 · 2010. Okt. 21. (Cs), 02.18
Karakterkódoláshoz kiegészítésként:
az UTF-8 kódolást a PHP beépített string kezelő függvényei nem támogatják maradéktalanul.
Rövid példa:
$str = 'őőő';
echo strlen($str);  // 6
echo mb_strlen($str, 'utf-8');  // 3

Ezt is odacsapnám a karakterkódolásos részhez, egyébként remek írás!
34

json_encode()

Szalbint · 2010. Nov. 7. (V), 21.51
Tényleg, a json_encode() működik már rendesen UTF-8 esetén?
Én kézzel kódolom, mert régebben nem működött, mostanában meg nem néztem.