Pagina 1 di 3 1 2 3 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 21
  1. #1
    Utente di HTML.it L'avatar di luca200
    Registrato dal
    Apr 2002
    Messaggi
    4,135

    [PILLOLA] Come gestire correttamente l'escape delle stringhe da inserire in un db

    Ovvero: "perché mi compaiono dei \ davanti agli apici sul database?"

    Quando si devono inserire stringhe in un database bisogna fare attenzione a farne correttamente l'"escape", cioè a "neutralizzare" quei caratteri che possono provocare problemi alla query di inserimento.

    Esempio: ipotizziamo di avere una tabella che contiene una colonna 'Cognome' e di dovere inserire il cognome D'Antoni.
    Ipotizziamo altresì di lavorare su MySql, il database più utilizzato in "combutta" con php. Il problema tuttavia si presenta in termini molto simili con qualsiasi tipo di database.

    Come ben sapete (se non lo sapete filate subito qui! ), per inserire una stringa in una istruzione sql bisogna racchiuderla tra apici. Ad esempio se il nostro cognome, invece di D'Antoni, fosse Antoni, l'istruzione sarebbe semplice:
    codice:
    ...cognome = 'Antoni', ...
    Ma cosa succede se facciamo questo?
    codice:
    ...cognome = 'D'Antoni', ...
    Semplice: il parser della query vede l'apice dopo la D e considera la stringa terminata. Quello che viene dopo porterà ad un errore, perché il linguaggio SQL non conosce la parola 'Antoni' che è rimasta fuori dagli apici.

    Ci deve essere però un modo per inserire un apice in una stringa!
    Ovviamente sì, ed è proprio l'escape di cui parlavamo.
    codice:
    ...cognome = 'D\\'Antoni', ...
    In questo caso il backslash, che è il "carattere di escape", fa sì che il carattere successivo venga considerato in quanto tale e non come carattere di chiusura della stringa, come sarebbe successo nel caso precedente.
    Il parser della query quindi capisce che l'apice fa parte della stringa e prosegue fino all'apice successivo, che determinerà la chiusura della stringa stessa. Ovviamente nel database verrà memorizzato D'Antoni, senza il backslash, in quanto il parser, dopo averlo "utilizzato" per interpretare correttamente la stringa, lo ha eliminato. Quindi quando andremo a rileggere il dato nel database otterremo esattamente il valore che ci interessa.

    Bene, ora passiamo a php. Come facciamo ad ottenere questo risultato, tenendo presente che quasi sempre i dati da mettere nel database sono contenuti in variabili di cui non conosciamo il contenuto nel momento in cui scriviamo il codice?
    Le possibilità sono diverse.

    La più tradizionale veniva fornita in automatico da php attraverso la direttiva magic_quotes_gpc del file php.ini.
    Quando tale direttiva è attivata, tutti i dati provenienti da querystring, moduli e cookie vengono, di fatto, sottoposti alla funzione addslashes(), che aggiunge un '\\' davanti agli apici singoli e doppi, nonché allo stesso backslash e agli eventuali caratteri NUL (byte nulli).
    Un altro modo di ottenere lo stesso risultato è, evidentemente, quello di applicare la funzione addslashes() vista sopra alle variabili che devono essere inserite nel database.
    In realtà però il sistema migliore per fare l'escape che ci serve è quello di usare (quando disponibile, ovviamente) la funzione apposita dedicata al database che ci interessa. Nel caso di MySql si tratta di mysql_real_escape_string() o di mysqli_real_escape_string() , a seconda di quale versione della libreria stiamo utilizzando. Alle funzioni devono essere passati come parametri la stringa di cui ci serve l'escape e l'identificativo di connessione al database (che quindi dobbiamo avere già effettuato). Attenzione! L'ordine dei parametri è rovesciato fra le due funzioni (la connessione va come secondo per mysql_real_escape_string, come primo per mysqli_real_escape_string; se si usa mysqli nella notazione a oggetto, la connessione ovviamente non serve).
    Tale funzione infatti tiene conto del character set attivo nella connessione, il che consente una maggiore precisione nell'identificazione dei caratteri di cui fare l'escape.

    Quindi, riassumendo, la soluzione migliore è:
    - magic_quotes_gpc disattivati
    - invece di addslashes(), usare mysql_real_escape_string() o equivalente, quando disponibile

    Ai più inesperti capita di trovarsi dei backslash nel database in corrispondenza di apici: se fate una SELECT sulla colonna che abbiamo visto prima e vi salta fuori D\\'Antoni, significa che l'operazione di escape è stata fatta due volte: infatti la funzione eseguita per seconda ha trovato il backslash già contenuto nella stringa e ha "creduto" che ne facesse parte, facendo quindi l'escape in modo che tale backslash non andasse perso nell'inserimento al db.
    Come può accadere questo?
    Il caso più frequente è sicuramente quello di un addslashes() (o altra funzione di escape come visto sopra) che è stata eseguita su una stringa di input (querystring, modulo o cookie) in presenza di magic_quotes_gpc attivo, il che porta la stringa ad essere processata due volte con il risultato che abbiamo appena detto.

    Il suggerimento già visto è quello di tenere disattivato magic_quotes_gpc. Tuttavia, per poter trattare i dati in maniera indipendente da questo, conviene avere una funzione che sia in grado di tenere conto dell'impostazione suddetta.
    Vediamo un breve esempio:
    Codice PHP:
    function strip_magic ($value)
    {
        
    $value = (get_magic_quotes_gpc()) ? stripslashes($value) : $value;
        return 
    $value;
    }
    $campo strip_magic($_POST['campo']); //ATTENZIONE: i campi di input vanno validati attentamente!!
    $campoPerDb mysql_real_escape_string($campo,$conn); 
    In questo piccolo esempio abbiamo definito una funzione (strip_magic()) che verifica se magic_quotes_gpc è attivato e, in caso affermativo, applica la funzione stripslashes() che fa l'opposto di addslashes() e quindi ne neutralizza l'effetto (in pratica rimuove dalla stringa gli eventuali backslash di escape).
    Dovendo trattare quindi un campo di input per inserirlo nel db, procederemo seguendo due fasi:
    1) neutralizzazione dell'eventuale magic_quotes_gpc (nell'esempio abbiamo usato direttamente il campo in input da un modulo, ma ricordatevi che non bisogna MAI fidarsi dell'input, bensì controllare sempre che contenga ciò che ci aspettiamo)
    2) applicazione della funzione di escape per neutralizzare eventuali apici

    Le due fasi vanno tenute ben distinte, perché non è detto che vadano sempre in coppia: infatti se abbiamo un dato in input che non deve essere memorizzato su database dovremo eseguire la prima ma non la seconda; nel caso invece in cui un dato vada memorizzato sul db ma non provenga dall'input utente (ad es. potrebbe essere appena stato letto da un altro db) allora dovremo eseguira la seconda e non la prima. E' infatti importante ricordare che la funzione stripslashes() deve essere eseguita solo su stringhe alle quali sia stata precedentemente applicata addslashes(); in caso contrario rischiamo di alterare la stringa originaria.


    E per stasera è tutto, la linea allo studio
    (se notate incongruenze fatemele notare perché il forum è un po' str@nzo e tende a mangiarsi i backslash... )

  2. #2
    Bella davvero ci voleva proprio..
    Dopo me la studio anche se adotto già un metodo simile..
    Questa volta, più che un voto.. è favoreggiamento.

  3. #3

  4. #4
    Utente di HTML.it L'avatar di Lak3d
    Registrato dal
    Aug 2006
    Messaggi
    1,049
    ottima! Peccato non abbia capito per quale motivo ritieni migliore il sistema con la direttiva magic quotes disattivata...

  5. #5
    Utente di HTML.it L'avatar di luca200
    Registrato dal
    Apr 2002
    Messaggi
    4,135
    Originariamente inviato da Lak3d
    ottima! Peccato non abbia capito per quale motivo ritieni migliore il sistema con la direttiva magic quotes disattivata...
    Per due motivi

    1) Le magic_quotes_gpc sono attualmente sconsigliate per motivi di performance (e non di sicurezza come ho visto dire da qualcuno sul forum)
    2) Le magic_quotes_gpc equivalgono ad applicare la funzione addslashes() mentre, come detto, è più preciso utilizzare la funzione specifica per il database, quando disponibile, come ad esempio mysql_real_escape_string()

  6. #6

    gestire l' escape delle stringhe da inserire nel db

    E' giusto fare anche così, in ogni caso?

    // formattaziore valori prima dell'inserimento nel db

    if(get_magic_quotes_gpc())
    {
    $numero =stripslashes($numero);
    $parola =stripslashes($parola);
    $tipo =stripslashes($tipo);
    $anno=stripslashes($anno);
    } else

    {
    $numero =mysql_real_escape_string($numero);
    $parola =mysql_real_escape_string($parola);
    $tipo =mysql_real_escape_string($tipo);
    $anno =mysql_real_escape_string($anno);

    }

  7. #7
    Utente di HTML.it L'avatar di luca200
    Registrato dal
    Apr 2002
    Messaggi
    4,135
    No.
    La prima parte è giusta.
    La seconda invece NON deve essere dentro l'else, perché va eseguita in ogni caso.

  8. #8
    grazie !
    hai perfettamente ragione , nel codice originale l'else non lo avevo messo, ma poi chissà perche l'ho aggiunto.

    un'altra domanda:
    - ho creato un form per un motore di ricerca all'interno di una tabella e ho filtrato i dati immessi dagli utenti con il codice su postato, ma non mi sembra sufficiente.
    Bisogna aggiungere altri controlli ,ad esempio prevedere che i numeri siano numeri le stringhe siano stringhe, che la maxlenght dei campi immessi sia rispettata, che altri caratteri particolari non possano essere immessi.
    Nell'ultimo caso qual'è il codice da usare per i caratteri particolari?

    - ho previsto inoltre la paginazione dei risultati nel caso in cui i record da mostrare sono tutti.
    In pratica supponiamo che nel form sia stato indicato solo l'anno e il tipo(hidden);
    tramite post invio alla pagina dei risultati e contestualmente faccio la paginazione di essi tramite get.
    In questo caso potresti indicarmi le funzioni da usare per 'bonificare' la query-string del tipo

    //http://miosito.it/tutte.php?anno=2004&Tipo=TIPO1&page=1 ?

    ho trovato questa pillola
    Constructing hyperlinks safely HOW-TO:

    <?php
    $path_component = 'machine/generated/part';
    $url_parameter1 = 'this is a string';
    $url_parameter2 = 'special/weird "$characters"';

    $url = 'http://example.com/lab/cgi/test/'. rawurlencode($path_component) . '?param1=' . urlencode($url_parameter1) . '&param2=' . urlencode($url_parameter2);

    $link_label = "Click here & you'll be <happy>";

    echo '', htmlspecialchars($link_label), '';
    ?>

    This example covers all the encodings you need to apply in order to create URLs safely without problems with any special characters. It is stunning how many people make mistakes with this.

    Shortly:
    - Use urlencode for all GET parameters (things that come after each "=").
    - Use rawurlencode for parts that come before "?".
    - Use htmlspecialchars for HTML tag parameters and HTML text content.

    e vorrei mi spiegassi cosa fanno in pratica queste funzioni.

    Io per ovviare il tutto avevo previsto di controllare che la pagina tutte.php non potesse essere eseguita da sola tramite questo controllo, ma non so se è sufficiente ad impedire un attacco.

    if (!isset($_SERVER['HTTP_REFERER'])) header("Location: -http://www.miosito.it/form.php.")

    Scusa per la lunghezza del post. Ti ringrazio anticipatamente.

  9. #9
    BUMP
    Addio Aldo, amico mio... [03/12/70 - 16/08/03]

  10. #10
    Ciao,

    io devo filtrare del testo inviato dagli utenti, che viene inserito nel database per poi essere pubblicato.

    Ho letto che bisognerebbe fare l’escape anche dei caratteri % e _. Siccome mysqli_real_escape_string() non lo fa, dopo di essa ho messo strtr() per ovviare al problema:

    Codice PHP:
    $post mysqli_real_escape_string($conn,$post);
    $post strtr($post, array('_' => '\_''%' => '\%')); 
    Però nel database vengono salvati i baskslash e quindi vengono visualizzati nella pagina davanti a % e _.

    Da questa tua pillola ho visto che potrebbe essere dovuto al fatto che l’escape dei due caratteri è stato eseguito due volte, e che quindi strtr() non servirebbe. Ma oltre a strtr() che cosa può essere stato ad eseguire l’escape dei due caratteri? Non può essere stata mysqli_real_escape_string() perché ho fatto una prova senza di essa e non cambia nulla.

    O forse, più semplicemente, % e _ non vengono considerati come caratteri sui quali eseguire l’escape e quindi un \ davanti ad essi viene trattato come un carattere normale? Ma in tal caso allora come mi devo regolare nei confronti di questi due caratteri?

    Grazie.

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 © 2019 vBulletin Solutions, Inc. All rights reserved.