Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 18
  1. #1

    [PILLOLINA] Richieste più sicure con il PHP

    Premessa
    La sicurezza nel web non è mai abbastanza ma soprattutto in prodotti Open Source è sempre meglio prendere tutte le precauzioni possibili per evitare che i malintenzionati possano far danni.

    Problema
    PHP lavora principalmente con le stringhe ed anche le richieste, GET, POST, REQUEST o altro, sono sempre e comunque gestite come stringhe.
    Tutti gli applicativi mediamente sicuri hanno uno o più metodi per verificare l'affidabilità di una richiesta al fine di evitare sql injections, request injections ed altro ancora.
    Ma qual'è il modo più semplice per fare questo ?

    Soluzione
    I dati inviati in una pagina sono anch'essi principalmente di tipo stringa ed il modo più sicuro per evitare problemi è fare verifiche dedicate per ogni tipo di dato.
    Un nome ad esempio non potrà contenere caratteri speciali, al massimo spazi ed apostrofi, quindi su una form contenente i soliti campi nome e cognome, la soluzione migliore potrebbe essere quella di verificare con una espressione regolare che la variabile inviata sia un match di questa stringa: "/^[a-zA-Z' ]+$/".
    Ogni altro campo potrebbe avere un tipo di controllo analogo o completamente diverso, il punto è che una giusta espressione regolare può essere in grado di scremare di suo un altissima percentuale di "tentativi maliziosi".
    A questo si deve aggiungere, per ogni query fatta in database, la corrispettiva funzione di escape (mysql_escape_string, sqlite_escape, eccetera ...).

    Definito quanto detto per le stringhe e stabilito quindi che fare una funzione contenente tutti i controlli per un tipo di campo piuttosto che un altro non avrebbe senso, restano gli altri utili e soliti valori da verificare.
    I dati di tipo int, float, o di tipo booleano, possono essere infatti parsati in modo molto semplice, sfruttando una espressione regolare dedicata ma sicuramente affidabile.

    Oltre a questo è possibile usare una funzione apposita per evitare anche di mostrare i soliti e fastidiosi notice negli script meno scrupolosi e che non si preoccupano delle possibili falle, dei possibili attacchi e dei possibili errori di codice.


    La funzione
    codice:
    // http://www.devpro.it/code/129.html
    function getRequest(&$method, $name, $type = null, $default = null) {
    	
    	/**
    	 *	getRequest(&$_GLOBAL:mixed, $name:string[, $type:string[, $default:mixed]]):mixed
             *
             * @param	mixed		super global array (i.e. $_POST, $_GET, $_REQUEST ... others)
             * @param	string		expected variable name (i.e. for $_GET["test"] the name "test")
             * @param	string		type of the value:
             * 					bool		verify if request is a boolean value (true/false/0/1)
             *					int		verify if request is an integer value (range, -N, N+)
             *					uint		verify if request is an unsigned integer (range, 0, N+)
             *					float		verify if request is a float number (range, -Z, Z+)
             *					serialized	verify if request is a real serialized value (returns unserialized value)
             *				[default null]
             * @param	mixed		default type for value [default null]
    	 */
    	$validTypes = array("bool", "int", "uint", "float", "serialized");
    	$result = $default;
    	if(isset($method[$name])) {		
    		if(!is_null($type) && in_array($type, $validTypes)) {
    			$method[$name] = trim($method[$name]);
    			switch($type) {
    				case "bool":
    					if(preg_match("/^(true|false|0|1)$/", $method[$name]))
    						$result = (bool)str_replace('false', '0', $method[$name]);
    					break;
    				case "int":
    					if(preg_match("/^([\-]?[0-9]+)$/", $method[$name]))
    						$result = (int)$method[$name];
    					break;
    				case "uint":
    					if(preg_match("/^([0-9]+)$/", $method[$name]))
    						$result = (int)$method[$name];
    					break;
    				case "float":
    					if(preg_match("/^[0-9]*(\.|\,)[0-9]+$/", $method[$name]))
    						$result = (float)str_replace(',', '.', $method[$name]);
    					break;
    				default:
    					$result = @unserialize($method[$name]);
    					if($result === false && $method[$name] !== serialize($result))
    						$result = $default;
    					break;
    			}
    		}
    		else
    			$result = &$method[$name];
    		
    	}
    	return $result;
    }

    L'utilizzo
    Se vogliamo usare una variabile $_POST, ad esempio $_POST["nome"], non dovremmo mai evitarne il controllo.
    Grazie a questa semplice funzione è possibile fare una chiamata come questa
    codice:
    $_POST["nome"] = getRequest($_POST, "nome");
    Assicurandoci che il server non mostri NOTICE da nessuna parte e restituendoci la stringa esatta, se esistente o il valore null, se la variabile non è stata inviata.
    Un semplice controllo subito dopo potrebbe darci la certezza che lo script lavorerà con una variabile e non con un "fantasma".
    codice:
    if($_POST["nome"]) ...
    
    #oppure in linea
    
    if(($_POST["nome"] = getRequest($_POST, "nome")) !== null) ...
    La funzione è anche in grado di restituirci tipi primitivi esattamente come ci servono.
    Vediamo un pò di esempi
    codice:
    // form con un checkbox con valore 1 per l'approvazione di qualcosa
    $booleano = getRequest($_POST, "approvato", "bool", false);
    // $booleano sarà una primitiva booleana true solo se il campo
    // di nome approvato esisteva e solo se conteneva il valore 1 o true
    // <input type="checkbox" name="approvato" value="true" /> approvo le condizioni
    
    
    // immaginiamo una select con degli id presi da un database.
    // tale select dovrà inviare sempre un intero maggiore di zero
    // per essere certi che un id è stato scelto ed inviato ...
    $selectid = getRequest($_POST, "dbid", "uint", 0);
    // solo se $selectid è maggiore o diverso da 0 saremo certi che l'utente ha scelto un id
    
    
    // un intero
    $miointero = getRequest($_POST, "prodotti", "int");
    // se $miointero sarà diverso da null sarà un numero intero valido
    
    
    // un float, scritto con la virgola o con il punto
    $miofloat = getRequest($_POST, "prodotti", "float");
    // se $miofloat sarà diversa da null sarà un numero float valido
    
    
    // in fine, unaserializzata
    $tantivalori = getRequest($_POST, "valori", "serialized");
    // solo se la variabile $_POST["valori"] esiste, è stata inviata, ed il suo contenuto è un valore correttamente serializzato, allora $tantivalori sarà una variabile valida.

    Conclusione
    La funzione mostrata diventa inutile se oltre i suoi controlli non si aggiungono le giuste verifiche per i dati di ingresso ma può aiutare ad evitare di scrivere ogni volta il solito controllo sul dato
    if(isset($_GET["nome"]) && $_GET["nome"] === ... )
    nonchè può aiutare ad evitare attacchi fastidiosi restituendo un valore di default e scremando quindi i dati non previsti che sempre grazie a questa funzione saranno restituiti come tipo primitivo già castato.
    Formaldehyde a new Ajax PHP Zero Config Error Debugger

    WebReflection @WebReflection

  2. #2
    up
    Formaldehyde a new Ajax PHP Zero Config Error Debugger

    WebReflection @WebReflection

  3. #3
    Utente di HTML.it L'avatar di luca200
    Registrato dal
    Apr 2002
    Messaggi
    4,120
    Io uso da anni un sistema simile ma con qualche funzionalità in più, attraverso il quale controllo rigorosamente tutto ciò che arriva in input (cioè che tutti i dati attesi siano presenti e che tutti i dati presenti siano attesi), prevedendo anche tipi diversi di dati (range di valori, valori compresi in liste).
    Da tempo avevo in mente di perfezionarlo e postarlo come pillola, magari trasformandolo in classe/i, ma come al solito cento ne penso e una ne faccio... e questa è ancora fra le 99

  4. #4
    Originariamente inviato da luca200
    Io uso da anni un sistema simile ma con qualche funzionalità in più, attraverso il quale controllo rigorosamente tutto ciò che arriva in input (cioè che tutti i dati attesi siano presenti e che tutti i dati presenti siano attesi), prevedendo anche tipi diversi di dati (range di valori, valori compresi in liste).
    Da tempo avevo in mente di perfezionarlo e postarlo come pillola, magari trasformandolo in classe/i, ma come al solito cento ne penso e una ne faccio... e questa è ancora fra le 99
    anche io da anni verifico tutto l'utile o l'utilizzato ma vedo ancora persone che non lo fanno e scrivono

    echo $_POST['pippo'];

    oppure

    mail($_POST['to'], $_POST['subject'], $_POST['mail']) ...

    e non verificano mai niente, quindi ovviamente la funzione per quanto semplice e la piccola spiegazione doveva essere più per i meno esperti che per te


    Ben vengano approfondimenti, metodi alternativi e/o più completi
    Formaldehyde a new Ajax PHP Zero Config Error Debugger

    WebReflection @WebReflection

  5. #5

    ...............

    Ciao.
    Penso che un approccio del
    genere sia migliore anche se
    sviluppato in maniera semplice (ne
    esistono di molto + complessi vedi validator
    class di Manuel Lemos (il mio idolo secondo
    solamente a Alejandro Gervaso
    Codice PHP:
    <?php

    abstract class validator
    {    
        protected 
    $_error;
        
        abstract  public function 
    validate();
        public function 
    getErrors()
        {
            return 
    $this->_error;
        }
            
    }

    //Vlaiding Emails
    class emailvalidator extends validator
    {    
        private 
    $_name;
        private 
    $_email;
        
        public function 
    __construct($name,$email)
        {
            
    $this->_name $name;
            
    $this->_email $email;

        }
        
        public function 
    validate()
        {
            
    $trimed_email trim($this->_email);
            if (!
    eregi("^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,8})$"$trimed_email))
            {
                
    $this->_error $this->_name.' is not formated Correctly';
                return 
    false;
            } else {
                return 
    true;
            }
        }
        
    }

    //Vlading for string to make sure they only include Text charchters
    class textOnlyvalidator extends validator
    {
        private 
    $_name;
        private 
    $_text;
        
        public function 
    __construct($name,$text)
        {
            
    $this->setName($name);
            
    $this->setText($text);
        }
        private function 
    setText($text)
        {
            
    $this->_text $text;
        }
        private function 
    setName($name)
        {
            
    $this->_name $name;
        }
        
        public function 
    validate()
        {
            
    $trimed trim($this->_text);
            if (
    preg_match("/\d/"$trimed))
            {
                   
    $this->_error $this->_name.' is not only text it includes numeric charcters';
                return 
    false;
            } else {
                return 
    true;
            }
        }
        
    }

    //Vlading for numeric
    class numericvalidator extends validator
    {
        private 
    $_name;
        private 
    $_num;
        
        public function 
    __construct($name,$num)
        {
            
    $this->setName($name);
            
    $this->setNum($num);
            
        }
        private function 
    setName($name)
        {
            
    $this->_name $name;
        }
        
        private function 
    setNum($num)
        {
            
    $this->_num $num;
        }
        
        public function 
    validate()
        {
            
    $trimed trim($this->_num);
        
            if (!
    is_numeric($trimed))
            {
                
    $this->_error $this->_name.' is not numeric';
                return 
    false;
            }
            else
            {
                return 
    true;
            }    
        }
            
    }

    class 
    textLengthvalidator extends validator
    {
        private 
    $_text;
        private 
    $_name;
        
        private 
    $_min 0;
        private 
    $_max;
        
        public function 
    __construct($name,$text,$max,$min 0)
        {
            
    $this->setName($name);
            
    $this->setText($text);
            
    $this->setMax($max);
            
    $this->setMin($min);
        }
        private function 
    setText($text)
        {
            
    $this->_text $text;
        }
        private function 
    setName($name)
        {
            
    $this->_name $name;
        }
        
        private function 
    setMax($max)
        {
            
    $this->_max $max;
        }
        
        private function 
    setMin($min)
        {
            
    $this->_min $min;
        }
        public function 
    validate()
        {
            
    $newtext trim($this->_text);
            
    $strlength strlen($newtext);
            if (
    $strlength $this->_max)
            {
                
    $this->_error$this->_name.' should only be '.$this->_max.' characters long';
                return 
    false;
            } elseif (
    $strlength <= $this->_min) {
                
    $this->_error $this->_name.' should be atleast '.$this->_min.' characters long';
                return 
    false;
            } else {
                return 
    true;
            }
        }
    }

    class 
    phoneNumbervalidator extends validator
    {
        private 
    $_number;
        private 
    $_name;
        
        public function 
    __construct($name,$num)
        {
            
    $this->setName($name);
            
    $this->setNumber($num);
        }
        
        private function 
    setName($name)
        {
            
    $this->_name $name;
        }
        
        private function 
    setNumber($num)
        {
            
    $this->_number $num;
        }
        public function 
    validate()
        {
            
    $trimed trim($this->_number);
            
            if (!(
    strlen($trimed) == 10) || !(is_numeric($trimed)))
            {
                
    $this->_error $this->_name.' is incorrect';
            } else {
                return 
    true;
            }
        }
    }


    $class[] = $email = new emailvalidator('User Email','asdfasdfs.com');
    $class[] = $text = new textOnlyvalidator('User name','Vitaly');
    $class[] = $num = new phoneNumbervalidator('Home Phone Number','51p27852155');
    $class[] = $len = new textLengthvalidator('Summary','adflas]kjflasjflskajflsadjflsdkjklsjflasjkdflasdjflsk aklsjfls adkjflsdjk f',100);
    $class[] = $num2 = new numericvalidator('Numbers','1h23');


    foreach (
    $class    as $v)
    {
        if (!
    $v->validate()) {
            echo 
    $v->getErrors().'
    '
    ;        
        }
            
        

    }
    ?>
    Semplice ma illuminante !
    Come si dice mi si è aperto
    un nuovo mondo
    Without faith, nothing is possible. With it, nothing is impossible
    http://ilwebdifabio.it

  6. #6
    Utente di HTML.it L'avatar di luca200
    Registrato dal
    Apr 2002
    Messaggi
    4,120
    Originariamente inviato da andr3a
    la funzione per quanto semplice e la piccola spiegazione doveva essere più per i meno esperti che per te
    non lo mettevo in dubbio, ma il 3d languiva...

  7. #7
    Originariamente inviato da andr3a
    up
    pure io uso un metodo del genere
    però addirittura per gli int verifico la positività del numero ..
    difficilmente ho id negativi sul db
    Soluzioni di Web marketing, CMS, Temi wordpress, grafica e molto altro

    -----
    Ogni topic aperto con un titolo errato fa perdere un capello al moderatore che lo dovrà sistemare.. se non vuoi contribuire alla calvizia dei moderatori apri 3D a norma di regolamento, e prima fai una ricerca! No pvt tecnici!

  8. #8
    Originariamente inviato da ringo_mato
    però addirittura per gli int verifico la positività del numero ..
    difficilmente ho id negativi sul db
    si ma il metodo deve essere portabile, se hai un carrello devi anche poter togliere interi.

    un int è un int, a te servono gli unsigned int (uint nella funzione) per i dati in db
    Formaldehyde a new Ajax PHP Zero Config Error Debugger

    WebReflection @WebReflection

  9. #9
    Salve a tutti.. riuppo la discussione xke è mooooooolto interessante..

    Volevo chiedere (ed in specifico a whisher), come faccio ad utilizzare tutto quel popo di codice???

    Allora io da niubbo ho creato il mio bel form di registrazione, quindi da li c'è la possibilità da parte di utenti esterni di inserire dati sul mio database e quindi di inserire anche dati ke potrebbero danneggiare il database .

    Ora io sempre da niubbo.. ho creato dei semplici controlli per vedere ad sempio se un campo è vuoto se l'email è valida ecc ecc..

    Ora leggo qua ke sarebbe sempre opportuno avere controlli ulteriori tipo quelli ke sono stati postati..

    E mo che mi servono e come li utilizzo in pratica (ricordate ke sono niubbo e nn ho capito na mazza)

    grazieeeeeeeeeeeeeeee
    Questa volta, più che un voto.. è favoreggiamento.

  10. #10
    Questa volta, più che un voto.. è favoreggiamento.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.