ugrás a tartalomhoz

Felhasználó által bevitt adatok megtisztítása

rockybro · 2009. Már. 21. (Szo), 21.41
Üdvözlet!

Felhasználó által bevitt adatokat kéne semlegesítenem és megtiszítanom egysmástól.

Elsődlegesen a html javascript php ésatöbbi kódokat kéne semlegesítenem benne... mert ugyebár, ha ezt nem teszem meg, akkor szépen átírhatja egy kedves user pl. a css-t, vegyünk például egy ilyet: <style type="text/css">*{display:none;}</style> , és utána csodálkozhatok, ha eltűnt az oldalam... hogyan lehet a kódokat semlegesíteni, hogy csak simán szövegként kezelve? a htmlspecialchars()-t kéne használnom?

ezután jöhet az escape-elés... erre van több függvény is: mysql_escape_string(), mysql_real_escape_string(), addslashes()... melyiket használjam, és mikor? mielőtt feltöltöm az adatokat az adatbázisba?

aztán jöhet a szépítés... ha a felhasználó által bevitt szöveg elejére és végére tesz néhány fölösleges szóközt, az könnyedén eltávolítható a trim() fügvénnyel... de ha a szöveg belsejében lévő szavak közé tesz túl sok szóközt, azt hogyan lehet eltávolítani? érdemes egyáltalán vele foglalkozni? ami érdekes számomra, hogy ha kiiratok egy lyukakkal (fölösleges szóközökkel) teli szöveget php-vel, akkor automatikusan leveszi a fölösleges szóközöket. ha beírtam 20 szóközt két szó közé, abból csak egyet ír ki. de közben meg ha feltöltöm adatbázisba, akkor ott ugyanúgy lyukas, mint ahogy eredetileg begépeltem.

tehát a lényeg: azt szeretném elérni, hogy a user akármilyen kódot, szimbólumokat, és bármit gépeljen is be, ne tudja meghackelni a beírt cuccokkal az oldalamat.

sok vendégkönyvnél láttam, hogy nem semlegesíti a kódokat, és 1 másodperc alatt ki lehetne lőni az egész oldalt egy aranyos kis scripttel.. nem akarok én is ilyen hibába esni.

Válaszokat előre köszönöm!
 
1

hoppá! az escape-es dologra

rockybro · 2009. Már. 21. (Szo), 21.59
hoppá! az escape-es dologra nagyjából megtaláltam a választ... de a többi kérdésem még mindig él... strip_tags() vagy htmlspecialchars()? ha escape-elek és bedobok egy strip_tags-ot is, akkor már teljes biztonságban érezhetem magamat?
2

egy kis elméleti maszlag

solkprog · 2009. Már. 21. (Szo), 22.48
Szerintem ne ész nélkül akard használni a fenti függvényeket. Mert nincs aranyszabály hogy ezt és ezt a függvényt használd mindenhova.

Ezért egy kis elméleti maszlag:
2 lehetősséged van ha szűrőd az adatokat (nem escape-eled):
- fekete listás szűrőt használsz. Vagyis azokat a karaktereket szűrőd amik kárt okozhatnak. Ez annyiban nem szerencsés mert "sose lesz teljes szűrés", így tökéletes védelem se. De ha ezt akarod használni akkor még véletlenül se saját kézzel akard megírni, hanem használd egyrészt a beépített függvényeket, másrészt letölthető szűrőket.
- Másik a fehér listás szűrés. Kitalálható módon itt a jó karaktereket megengedjük és minden mást meg eldobunk. Vagyis egyesével megírsz minden szűrést, amit célszerű RegExp-el megoldani. (felhasználónévbe elég az abc, számok, meg néhány nem veszélyes spéci karakter, minden mást lehet tiltani)

Nyilván valahol nem "szabad" minden káros karaktert kiszűrni, például egy matematikai témával foglakozó fórumon rendszerében nem lehet kiszűrni a < karaktert a hozászolásokból. Itt escape-eled őket. De fontos hogy ha nem kell a például < karakter akkor egyáltalán ne engedjük meg nekik, még escape-elve se. Például felhasználónévbe mi a fenének?

SQL injection (SQl befecskendezés) ellen nyilván az adatbázisba történő írás előtt kell védekezni. De arról lehet vitatkozni hogy az XSS ellen, mikor. Én azok közé tartozok akik szerint akkor amikor kiolvassuk az adatokat mert, máshogy kell szűrni/escape-elni egy html-be írt szöveget mint egy pdf-be...

üdv,
Balázs
3

aranyszabály

erenon · 2009. Már. 21. (Szo), 23.09
Aranyszabály:
adatbázisba felvétel előtt mysql_real_escape_string()
kiolvasás után kiiratás előtt htmlentities()
4

lényegretörő

rockybro · 2009. Már. 21. (Szo), 23.39
hmm... ez egyszerű és lényegretörő... szóval adatbázisba felvétel előtt kizárólag a mysql_real_escape_string()-et kell használnom, még akkor is ha vmi hiperszuper gonosz kóddal van dolgom? ez a függvény mindenhol működik? kipróbáltam a htmlentities()-t és a htmlspecialchars()-t egyaránt, a különbséget a kettő között itt láthatjátok: htmlspecialchars() vs. htmlentities() (gyorsan készítettem hozzá egy összehasonlító cuccost)
6

htmlspecialchars elég

Hodicska Gergely · 2009. Már. 22. (V), 15.00
A htmlentites fölösleges, nem erre a célra való. Kimenet megvédésére a hmlspecialcharst kell használni.
7

Na pont ezért írtam.

solkprog · 2009. Már. 22. (V), 16.53

SELECT * FROM tabla
WHERE
id=$id
A fenti kódba csak ennyi a befecskendezés: 1 or 1=1
Ész nélkül a mysql_real_escape_string() se ér semmit. (És akkor nem beszéltünk a % és a _ jelről)

üdv,
Balázs
8

akkor mi a helyzet?

rockybro · 2009. Már. 22. (V), 17.41
na akkor most mi a helyzet a mysql_real_escape_string()-gel? hogyan kéne használni? mi a végső konklúzió?
9

idézőjelek, típuskényszerítés

gex · 2009. Már. 22. (V), 17.54
egyrészt pp írta a típuskényszerítést, ami így néz ki:

<?php
echo (int)'1 or 1=1'; // kimenete: 1
?>
másrészt idézőjelet vagy aposztrófot írunk a sztring köré, azaz a te példád alapján (típuskényszerítés nélkül) ez

SELECT
    *
FROM
    tabla
WHERE
    id = '$id' -- kimenete: id = '1 or 1=1'
lenne. nem tudom itt mi a probléma. a mysql_real_escape_string nem a kifelejtett idézőjelektől/aposztrófoktól vagy emberi hülyeségtől véd, hanem például a szövegben szereplő időzőjelektől/aposztrófoktól. egy valós sql injection esetén az $id tartalma 1' or '' = ' lenne, aminek a kimenete id = '1' or '' = ''.

az említett _ és % jelek ellen pedig elég egy

<?php
$string = preg_replace('/([\\\\%_])/', '\\\\$1', $string);
?>
parancs, viszont erre meg csak a like-kal való összehasonlításnál van szükség.
10

:)

solkprog · 2009. Már. 22. (V), 18.48
"egyrészt pp írta a típuskényszerítést, ami így néz ki"
- De én nem pp válaszára reagáltam. erenon szerintem meg nem túl szerencsésen azt sugallta hogy a kérdező használja a mysql_real_escape_string() és a htmlentities() függvényeket és akkor biztonságban lesz. Erre reagáltam.

"másrészt idézőjelet vagy aposztrófot írunk a sztring köré"
- az id az numerikus. Innentől elkezdve nem feltétlen kell oda aposztróf. Viszont aposztróf nélkül meg a mysql_real_escape_string függvény nem sokat védd SQL befecskendezés ellen. (nem feltétlen csak aposztróffal lehet SQL injection elérni. Márpedig mysql_real_escape_string() kb csak ezt szűri ki...)

üdv,
Balázs
11

meddő vita

gex · 2009. Már. 22. (V), 19.19
ha a kérdező a mysql_real_escape_stringet használja (igen, aposztróffal) mind a szöveges mind a numerikus értékekhez, akkor biztonságban lesz.

ha majd azon is elgondolkozik, hogy a numerikus értékekhez erőforrás-pazarlás ezt a függvényt használni, akkor majd elgondolkozik azon is, hogy milyen más módon ellenőrizze a bejövő adatot. erre pedig jó lesz a típuskonverzió.

Ész nélkül a mysql_real_escape_string() se ér semmit.
de. csak némely esetben erőforrás-pazarló.
12

nem

solkprog · 2009. Már. 22. (V), 20.35

$_GET['id']='1 or 1=1';
$id=mysql_real_escape_string($_GET['id']);

SELECT * FROM adatok
WHERE id=$id

//az eredmények kilistázássa
1 or 1=1 ben nincs aposztróf de ugyanúgy tudd veszélyes lenni. A mysql_real_escape_string() meg nem csinál vele semmit.
Ész nélkül a mysql_real_escape_string() se ér semmit.
még mindig tartom (és szándékosan túlzó a mondat.)
Egyébként csak nekem a "mániám" a biztonság?

üdv,
Balázs
13

aposztróf...

gex · 2009. Már. 22. (V), 20.42
SELECT * FROM adatok WHERE id=$id helyett még mindig SELECT * FROM adatok WHERE id='$id'.
16

még mindig elbeszélünk egymás mellett..

solkprog · 2009. Már. 23. (H), 16.02
Az a baj hogy még mindig elbeszélünk egymás mellett. A MySQL-ben legalábbis megengedett hogy aposztróf nélkül használd a kiértékeléseket abban az esetben ha numerikus mezőket hasonlítasz össze. (nekem elvileg még így is tanították) Oké hogy célszerű kitenni az aposztrófokat biztonsági kérdés miatt, de anélkül se fog hibát dobni a DB-é! (a legjobb tudomásom szerint) És ha nem kell akkor sok programozó, úgy van vele hogy miért is tegye ki...

Én még mindig csak arra a kérdésre akarok rámutatni hogy ha nem vagyunk elégé figyelmesek akkor akár a mysql_real_escape_string() se csinál tökéletes védelmet bizonyos esetekben. (Például ha nem tesszük ki az apósztófott numerikus összehasonlításnál akkor ott bizony hiába használjuk a mysql_real_escape_string() nem fog "semmit" érni) És ezért nem szeretem ha azt mondják hogy használd ezt és ezt a függvényt és akkor biztonságba leszel. (Innen indult ez a "vita" is)

üdv,
Balázs
17

meddő vita #2

gex · 2009. Már. 23. (H), 16.35
És ha nem kell akkor sok programozó, úgy van vele hogy miért is tegye ki...
szerinted aki megkérdezi hogy mi az az sql injection egyáltalán, az majd ilyeneken gondolkozik?

szerintem kezdőknek kiváló tanács, hogy mindenhez aposztróf és mysql_real_escape_string, aztán ha majd mélyebben is érdekli akkor ellenőrzi máshogy a numerikus értékeket. ennyi, részemről lezárva, felesleges szájtépés ez már.
19

ez már tényleg az:)

solkprog · 2009. Már. 23. (H), 20.19
"szerinted aki megkérdezi hogy mi az az sql injection egyáltalán, az majd ilyeneken gondolkozik?"
- Ha nem tudja hogy veszélyes is lehet, akkor a válaszom igen. Azért is járattam a szám ennyit, hogy tudja. [mondom a biztonság a mániám]

"felesleges szájtépés ez már"
- egyetértek. A téma részemről is lezárva.

üdv,
Balázs
20

nem volt fölösleges szájtépés

rockybro · 2009. Már. 24. (K), 16.35
nem volt fölösleges a vitátok... én okosodtam belőle... egyébként igen, pár nappal ezelőtt még azt sem tudtam, hogy mi az az sql injection, de mostmár köszönhetően nektek és a linkeknek, amiket küldtetek, sokkal okosabb lettem. egyébként én is úgy vagyok a dolgokkal, hogy ha megtudom, hogy ez még így nem tökéletes, lehetne jobban is, akkor utánaolvasok, utánaérdeklődöm, és addig nem nyugszom, amíg nem lesz tökéletes.

írtam egy kódot:

<?php
$kapcsolat = mysql_connect('', '', '');
mysql_select_db('', $kapcsolat);
if ($_REQUEST['id']){
	$id = (int)$_REQUEST['id'];
	if ($id == 0){
		echo "Érvénytelen kérés!";
	} else {
		$lekerdezes = "SELECT * FROM bejegyzesek WHERE id = $id";
		$eredmeny = mysql_query($lekerdezes, $kapcsolat);
		if (mysql_num_rows($eredmeny) == 1){
			echo "Létező id!";
		} else {
			echo "Nem létező id!";
		}
}
}
?>
itt nem láttam szükségesnek, hogy escapeljem az id-t, és bármi mást csináljak vele, mivel már úgyis rákényszerítettem az integer típust, szóval már nem maradhat benne semmi gonosz kód... megfelelő?
21

talán nem.

solkprog · 2009. Már. 25. (Sze), 19.21
...nem maradhat benne semmi gonosz kód.
talán nem. de ha kicsit akkarok kötekedni akkor ennyi:
- db kapcsolódás létrejöttét ellenőrizd. Meg a query-t is.
- Mínusz számokat is szűrd. Bár tudom akkor azt fogja kiadni hogy "Nem létező id!".
Ha meg tényleg nagyon-nagyon akkor kötekedni:
if (isset($_REQUEST['id'])) { // isset fg ellenőrzi a változó létezését.    
     $id = (int)$_REQUEST['id'];  
     if ($id <= 0) { //Minusz számokat is szűrjük ki. 
         echo "Érvénytelen kérés!";  // Nem feltétlen kell ennyire részletesen közölni az userrel a hiba természetét.
     } else {  
         $lekerdezes = "SELECT * FROM bejegyzesek WHERE id = $id";  
         $eredmeny = mysql_query($lekerdezes, $kapcsolat);  
         if (mysql_num_rows($eredmeny) === 1) {  // Na ez tényleg csak kötözködés a részemről! (de csak ebben az esetben, mert általában nem mindegy hogy dupla vagy tripla az egyenlőségjel.)
             echo "Létező id!";  
         } else {  
             echo "Nem létező id!";  
         }  
 }  
}    
üdv,
Balázs
22

a db kapcsolódást és a queryt

rockybro · 2009. Már. 25. (Sze), 21.12
a db kapcsolódást és a queryt itt szándékosan nem írtam le, mert itt nem erre raktam a hangsúlyt.. de egyébként mindig szoktam ellenőrizni. köszönöm a kódot!
18

intval?

Szekeres Gergő · 2009. Már. 23. (H), 18.59
intvalozd a numerikus típusokat, a többire pedig escape... szerintem ezen kár összeveszni.

Ha meg valaki nem teszi ki az aposztrófokat, és úgy gondolja, hogy a mysql_real_escape megvédi, az nyilván rosszul gondolja, viszont szerintem a fejlesztők kis százaléka használja "nyersen" ezt a fv. escapelésre (remélem). Ugyanis ez mysql specifikus, amit mondjuk célszerű elrejteni egy másik rétegbe. Ha meg már úgy is van egy escape fvünk, az akár az aposztrófokat is kirakhatja helyettünk (a numerikusokat meg integerré alakítja), a 'query builder', és egyjéb db specifikus metódusokról meg ne is beszéljünk...
5

Sose bízz a felhasználótól jövő adatban.

pp · 2009. Már. 22. (V), 08.05
Ez az egy szabály van.

Két helyre tolod az adatokat. A kimenetre, ami HTML lesz általában. Itt az ún XSS támadástól kell tartanod. A legegyszerűbb a htmlspecialchars() használata, mert ez minden speciális html karaktert lecserél a neki megfelelő HTML entityre. A strip_tags() elvileg arra lenne jó, hogy csak bizonyos html elemeket hagyj a kódban, a többit kidobja. Sajnos nem a legtökéletesebb megoldás ezért én a használatát nem javaslom.
Elképzelhető, hogy nem sima szöveget kell kitolnod, hanem egy url-t. Ilyen eset lehet, ha egy képet (src="$var"), vagy egy link hivatkozást(href="$var") akarsz dinamikusan megjeleníteni. Ilyenkor az urlescape() függvényt érdemes használni. Minden más esetben valamilyen mintaillesztéssel tudod megoldani a problémát. (preg_*)

A másik kimenet amikor az adatbázis fele tolod az adatot. Itt az un. SQL injection támadástól kell tartanod. Ilyenkor mindig a megfelelő függvénnyel kell escapelned az adatokat. Mysqlnél és szövegnél én a mysql_real_escape_string() függvényt szoktam használni, míg egész számnál egyszerűen típuskényszerítek. pl.: (int)$var
Az addslashes() függvényt felejtsd el, mert egyrészt nem véd minden hiba ellen, másrészt pl. Oracle adatbázisnál nem így kell escapelned. (vagyis egy olyan rossz viselkedés mintát sajátítasz el ami később komoly problémákhoz vezethet)

Ezek a minimumok.

A sok szóközös dologról már gondolom tudod, hogy a böngésző a sok szóközt csak egynek jeleníti meg. Mindig nézz bele a forrásba, mert azt gyártottad a PHP-val.

A htmlentities() függvény meg nem rontja el a karaktereket egyszerűen rossz kódolást használsz. Próbáld ki, állítsd át a böngésződet iso-8859-2 formátumra és máris nem rontja el a szöveget a htmlentitites(). Te utf-8 karakterkódolást használsz, ami egy magyar ékezetes karaktert több bájttal ír le. Erről a függvény nem tud, ezért minden bájtot(mely számára ugye csak egy karakter) átalakít. Használd az mb_* függvényeket, ha utf-8 karakterkészlettel dolgozol!

pp
14

strlen

NiGGa · 2009. Már. 22. (V), 23.52
nem tudom ez mennyiben értelmes megoldás, de:
mivel ha te írsz meg egy oldalt, akkor valószínűleg tudod, hogy mit kérsz le, például
sdf.php?id=5
és várhatóan hány számjegyű lesz, persze később növelhető.
if (strlen($_GET["id"]) > 5){
    ip bann;
    die();
}else{
    $id = $_GET["id"];
}
15

select vs insert/update

gex · 2009. Már. 23. (H), 00.09
ez számokra működhet (mondom ezt úgy, hogy a jelenlegi téma azonosítója már 6 számjegy ami akár elég is lehet egy sql injection-höz). de regisztrációnál, bejelentkezésnél, hozzászólásnál nem sokat segít.