Validációs tervezési hibák
Szép napot!
Kíváncsi vagyok, hogy mit gondoltok a php validációról. Jó, ténylegesen nincs ilyesmi, de én nagyon furcsának találtam az alapvető hozzáállást a validáláshoz az összes kódban, amit eddig láttam. Gyakorlatilag már a kiindulásnál elbuknak, mert eleve rossz stratégiát választanak.
Alapból valahogy így szokás nekifutni php-ben a validálásnak:Symfony dokumentációból másolt kód - Form-Validation
Ez még a szerencsésebb eset. A szerencsétlenebb az, amikor külön controller-ben van a validáció és külön view-ban az űrlap létrehozása, és lapozgatni kell egyikről a másikra, hogy lássuk mi micsoda.
Miért rossz ez (legalábbis szerintem)?
Ha security-ről van szó általában mindenki a whitelist-es megoldásokat biztonságosabbnak tartja, mint a blacklist-eseket, mert könnyű kifelejteni, embereket, akiknek tiltani akarjuk az alkalmazás használatát. Ugyanígy input esetében ha nem kötelező megadni validációt minden egyes input-ra, akkor könnyű kifelejteni azt, és az alkalmazás ugyanúgy működni fog nélküle...
Szóval szerintem alapvetően téves az az elképzelés, hogy az input-okat blacklist-es megközelítéssel kellene kezelni. Helyette minden egyes input-ot regisztrálni kell a controller-ben, mint engedélyezettet, és ha a listán nem szereplő input is bejön, akkor a rendszer automatikusan dobhat egy BadRequestException-t. (Nem tudom létezik e olyan keretrendszer, ami ezt a megközelítést vallja, eddig nem találkoztam vele.)
Ti mit gondoltok erről?
■ Kíváncsi vagyok, hogy mit gondoltok a php validációról. Jó, ténylegesen nincs ilyesmi, de én nagyon furcsának találtam az alapvető hozzáállást a validáláshoz az összes kódban, amit eddig láttam. Gyakorlatilag már a kiindulásnál elbuknak, mert eleve rossz stratégiát választanak.
Alapból valahogy így szokás nekifutni php-ben a validálásnak:
// lib/form/ContactForm.class.php
class ContactForm extends sfForm
{
protected static $subjects = array('Subject A', 'Subject B', 'Subject C');
public function configure()
{
$this->setWidgets(array(
'name' => new sfWidgetFormInput(),
'email' => new sfWidgetFormInput(),
'subject' => new sfWidgetFormSelect(array('choices' => self::$subjects)),
'message' => new sfWidgetFormTextarea(),
));
$this->widgetSchema->setNameFormat('contact[%s]');
$this->setValidators(array(
'name' => new sfValidatorString(array('required' => false)),
'email' => new sfValidatorEmail(),
'subject' => new sfValidatorChoice(array('choices' => array_keys(self::$subjects))),
'message' => new sfValidatorString(array('min_length' => 4)),
));
}
}
Ez még a szerencsésebb eset. A szerencsétlenebb az, amikor külön controller-ben van a validáció és külön view-ban az űrlap létrehozása, és lapozgatni kell egyikről a másikra, hogy lássuk mi micsoda.
Miért rossz ez (legalábbis szerintem)?
Ha security-ről van szó általában mindenki a whitelist-es megoldásokat biztonságosabbnak tartja, mint a blacklist-eseket, mert könnyű kifelejteni, embereket, akiknek tiltani akarjuk az alkalmazás használatát. Ugyanígy input esetében ha nem kötelező megadni validációt minden egyes input-ra, akkor könnyű kifelejteni azt, és az alkalmazás ugyanúgy működni fog nélküle...
Szóval szerintem alapvetően téves az az elképzelés, hogy az input-okat blacklist-es megközelítéssel kellene kezelni. Helyette minden egyes input-ot regisztrálni kell a controller-ben, mint engedélyezettet, és ha a listán nem szereplő input is bejön, akkor a rendszer automatikusan dobhat egy BadRequestException-t. (Nem tudom létezik e olyan keretrendszer, ami ezt a megközelítést vallja, eddig nem találkoztam vele.)
Ti mit gondoltok erről?
Model
Jó kérdés
De azt viszonylag könnyen ellenőrizheted, hogy hány darab adat jött. A többi már a további validálás dolga.
Egyébként nem vagyok híve a 4xx dobálásnak, mert pl. előfordulhat, hogy megjelenik itt egy cikk, belinkelik valahol, majd törlik a cikket. Ekkor barátságosabb a cikk helyére odaírni, hogy "nincs megjeleníthető tartalom" (esetleg plusz magyarázattal), mint dobni egy 404-et.
A legtöbb esetben a whitelist-es ellenőrzés a megfelelő, egy-egy nagyon egyszerű esetben alkalmazható a blacklist-es is (pl. ha az adat nem integer), de nem követendő példa, épp azért, mert az összes nemet sokkal nehezebb felsorolni (és ahogy mondod, kihagyni könnyű belőle), mint az összes igent.
Whitelist
Ugyanakkor azokat az adatokat, amiket nem vár az alkalmazásod, azokat pedig eldobja (nem csinál velük semmit, igy elvesznek). Ellenőrizheted a bejövő adatokat valahol a feldolgozási folyamat elején, de alapvetően nagyobb (és nem szükséges) terhelésnek teszed ki a szervert, a biztonsági előnyök nélkül (hiszen a nem várt adattal úgy sem foglalkozol).
Egyáltalán nem az, mert
Ha meg direktbe $_GET-et használsz valahol, akkor lehet, hogy egyáltalán fel sem tűnik, hogy nincs levalidálva. Szóval lehet még fokozni...
Valami ilyesmire gondoltam js-el kifejezve. (valamiért most nem volt kedvem php-t írni)
- ha egy input nem szerepel az allow listában, de mégis megadják
- ha egy input-ra nincs típus meghatározva
- ha invalid a bejövő input
Az allow részben lévő beállításokat hozzá lehetne csapni a controller action-ökhöz annotáció formájában.
Az űrlapot lehetne úgy generálni, hogy ezeket az annotációkat is felhasználja. Így már a view példányosításánál elszállna, ha valamelyik input mező nincs engedélyezve az action annotációjában.
Szerintem ez lenne kielégítő biztonsági szempontból. Ami problémás, hogy nem egyszerű ilyen annotációkat tervezni, programkóddal sokkal könnyebb bekonfigolni valamit, mint annotációval vagy config fájlal...
Symfony
Pont az általad felhozott symfony 1.x framework tudott ilyet. A validátornak be lehetett állítani két opciót:
allow_extra_fields: Ha olyan input érkezik amihez nem tartozik validátor akkor hibát dob (hogy pontosan milyet arra már nem emlékszem sajnos)
filter_extra_fields: Kiszűri a formon nem megtalálható mezőket a postból és törli őket
Köszi, ezek hasznos dolgok,