Sanificazione e validazione dei dati con WordPress

Una sicurezza adeguata è fondamentale per mantenere al sicuro il tuo sito o quello del tuo tema o degli utenti plug-in. In parte ciò significa convalida e sanificazione dei dati appropriati. In questo articolo vedremo perché questo è importante, cosa deve essere fatto e quali funzioni fornisce WordPress per aiutare.

Poiché sembrano esserci varie interpretazioni su cosa significano i termini "validazione", "fuga" e "sanificazione", chiarirò innanzitutto cosa intendo in questo articolo:

  • Validazione - Questi sono i controlli che vengono eseguiti per garantire i dati avere è quello che dovrebbero essere. Ad esempio, che una e-mail assomiglia ad un indirizzo e-mail, che una data è una data e che un numero è (o è stato castato come) un numero intero
  • Sanificazione / fuga - Questi sono i filtri applicati ai dati per renderli "sicuri" in un contesto specifico. Ad esempio, per visualizzare il codice HTML in un'area di testo, sarebbe necessario sostituire tutti i tag HTML con i relativi equivalenti di entità

Perché la sanitizzazione è importante?

Quando i dati sono inclusi in un determinato contesto (ad esempio in un documento HTML), tali dati potrebbero essere interpretati erroneamente come un codice per quell'ambiente (ad esempio il codice HTML). Se tali dati contengono codice dannoso, quindi l'utilizzo di tali dati senza sanitarli, significa che il codice verrà eseguito. Il codice non deve necessariamente essere dannoso perché possa causare effetti indesiderati. Il compito di disinfettare è quello di assicurarsi che qualsiasi codice nei dati non sia interpretato come codice, altrimenti potresti finire come la scuola di Bobby Tables ...

"Exploits of a Mom" ​​- xkcd

Un esempio apparentemente innocuo potrebbe essere il pre-riempimento di un campo di ricerca con il termine attualmente interrogato, utilizzando il carattere senza caratteri di escape $ _GET [ 's']:

 

Ciò apre una vulnerabilità che potrebbe consentire l'iniezione di javascript, ad esempio, inducendo qualcuno a visitare http://yoursite.com?s= "/>. Il termine di ricerca 'salta' fuori dall'attributo value e la parte seguente dei dati viene interpretata come codice ed eseguita. Per evitare ciò, WordPress fornisce get_search_query che restituisce la query di ricerca sterilizzata. Anche se questo è un esempio "innocuo", lo script inserito potrebbe essere molto più dannoso e nella migliore delle ipotesi si limiterebbe a "spezzare" il form se i termini di ricerca contengono virgolette doppie.

In che modo questo codice dannoso (o altrimenti) potrebbe essersi trovato sul tuo sito non è la preoccupazione qui - ma piuttosto è per impedirne l'esecuzione. Né facciamo ipotesi sulla natura di questo codice indesiderato, o il suo intento - potrebbe essere stato semplicemente un errore da parte dell'utente. Questo mi porta alla regola n. 1 ...


Regola numero 1: Trust Nobody

È una massima comune che viene utilizzata per la sanitizzazione dei dati, ed è buona. L'idea è che non si dovrebbe assumere che tutti i dati inseriti dall'utente siano sicuri. Né dovresti presumere che i dati che hai recuperato dal database siano sicuri, anche se lo hai reso "sicuro" prima di inserirlo lì. In effetti, se i dati possono essere considerati "sicuri" non ha senso senza contesto. A volte gli stessi dati possono essere utilizzati in più contesti sulla stessa pagina. I titoli, ad esempio, possono tranquillamente contenere virgolette o virgolette quando si trovano all'interno dei tag di intestazione, ma causano problemi se utilizzati (senza caratteri di escape) all'interno di un attributo titolo di un tag di collegamento. Pertanto, è piuttosto inutile rendere i dati "sicuri" quando vengono aggiunti al database, poiché spesso è impossibile rendere i dati sicuri per tutti i contesti contemporaneamente. (Ovviamente deve essere reso sicuro da aggiungere al database - ma ci arriveremo più tardi).

Anche se si intende utilizzare tali dati in un contesto specifico, ad esempio un modulo, è ancora inutile disinfettare i dati durante la scrittura nel database poiché, come da Regola n. 1, non ci si può fidare che sia ancora sicuro quando si tiralo fuori di nuovo.


Regola n. 2: Convalida in entrata, Fuga in uscita

Questa è la massima procedurale che stabilisce quando è necessario convalidare i dati e quando si sanifica. In poche parole - convalida i tuoi dati (controlla che sia quello che dovrebbe essere - e che sia "valido") non appena lo ricevi dall'utente. Quando si arriva a utilizzare questi dati, ad esempio quando si esegue l'output, è necessario sfuggire (o disinfettarli). La forma di questa sanificazione dipende interamente dal contesto in cui la si utilizza.

Il miglior consiglio è di eseguire questo "in ritardo": sfuggire i dati immediatamente prima di utilizzarli o visualizzarli. In questo modo puoi essere sicuro che i tuoi dati sono stati correttamente disinfettati e non è necessario ricordare se i dati sono stati precedentemente controllati.


Regola n. 3: fiducia in WordPress

Si potrebbe pensare "Ok, convalidare prima di scrivere nel database e disinfettare quando lo si usa, ma non è necessario assicurarsi che i dati siano sicuri da scrivere nel database?". In generale, . Quando si aggiungono dati a un database, o semplicemente si utilizza un input per interagire con un database, è necessario sfuggire ai dati in cui è contenuto qualsiasi comando SQL. Ma questo mi porta alla Regola numero 3, una che vola in faccia alla Regola numero 1: Trust WordPress.

In un precedente articolo, ho preso l'input dell'utente (inviato da un modulo di ricerca tramite AJAX) e l'ho usato direttamente con get_posts () per restituire i post che corrispondono a quella query di ricerca:

 $ posts = get_posts (array ('s' => $ _ REQUEST ['term']));

Un lettore attento ha notato che non avevo eseguito alcuna sanificazione - e avevano ragione. Ma non avevo bisogno di farlo. Quando si utilizzano funzioni di alto livello come get_posts (), non è necessario preoccuparsi di disinfettare i dati, perché le query del database sono tutte correttamente escapate dagli interni di WordPress. È una questione completamente diversa se si utilizza una query SQL diretta, ma vedremo questo in una sezione successiva. Allo stesso modo, funzioni come il titolo(), the_permalink (), il contenuto() ecc. eseguono la loro sanificazione (per il contesto appropriato).


Convalida dei dati

Quando si ricevono dati inseriti da un utente è importante convalidare esso. (L'API delle impostazioni, trattata in questa serie, consente di specificare una funzione di callback per fare esattamente questo). I dati non validi sono corretti automaticamente, oppure il processo viene interrotto e l'utente viene restituito al modulo per riprovare (eventualmente con un messaggio di errore appropriato). La preoccupazione qui non è la sicurezza, ma piuttosto la validità: se lo stai facendo bene, WordPress si occuperà di aggiungere i dati in modo sicuro al database. Che cosa significa "valido" dipende da te: potrebbe significare un indirizzo email valido, un intero positivo, un testo di lunghezza limitata o uno di un array di opzioni specificate. Tuttavia, il tuo scopo è determinare la validità, WordPress offre molte funzioni che possono aiutarti.

Numeri

Quando si aspettano dati numerici, è possibile verificare se i dati "sono una forma di numero", ad esempio is_int o is_float. Solitamente, è sufficiente trasmettere semplicemente i dati come numerici con: intval o floatval.

Se è necessario assicurarsi che il numero sia riempito con zeri iniziali, WordPress fornisce la funzione zeroise (). Quale prende i seguenti parametri:

  • Numero - il numero da riempire
  • Soglia - il numero di cifre a cui verrà inserito il numero

Per esempio:

 echo zeroise (70,4); // Stampa 0070

Le e-mail

Per verificare la validità delle e-mail, WordPress ha il is_email () funzione. Questa funzione utilizza semplici controlli per convalidare l'indirizzo. Ad esempio, controlla che contenga il simbolo '@', che sia più lungo di 3 caratteri, che il dominio contenga solo caratteri alfa e trattini e così via. Ovviamente, non controlla che l'indirizzo e-mail esista effettivamente. Supponendo che l'indirizzo e-mail abbia superato i controlli, viene restituito, altrimenti viene restituito 'falso'.

 $ email = is_email ('eomeone@e ^ esempio.com '); // $ email è impostato su false. $ email = is_email ('[email protected] '); // $ email è impostato su "[email protected]".

HTML

Spesso si potrebbe desiderare di consentire solo alcuni Tag HTML nei tuoi dati, ad esempio nei commenti pubblicati sul tuo sito. WordPress fornisce una famiglia di funzioni del modulo wp_kses_ * (KSES Strips Evil Scripts). Queste funzioni rimuovono (alcuni sottoinsiemi di) tag HTML e possono essere utilizzati per garantire che i collegamenti nei dati siano di protocolli specifici. Ad esempio il wp_kses () la funzione accetta tre argomenti:

  • soddisfare - (stringa) Contenuto da filtrare tramite kses
  • allowed_html - Un array in cui ogni chiave è un elemento HTML consentito e il valore è una matrice di attributi consentiti per quell'elemento
  • allowed_protocols - Opzionale. Protocollo consentito nei collegamenti (ad esempio http, mailto, alimentazione eccetera.)

wp_kses () è una funzione molto flessibile che consente di rimuovere tag indesiderati o solo attributi indesiderati dai tag. Ad esempio, per consentire solo o tag (ma ammetti solo l'attributo href):

 $ content = "Clic qui da visitare  wptuts+ "; echo wp_kses ($ content, array ('strong' => array (), 'a' => array ('href'))); // Stampa l'HTML" Fai clic qui per visitare  wptuts+ ": Clicca qui per visitare  wptuts+ 

Ovviamente, specificare ogni tag consentito e ogni attributo consentito può essere un compito laborioso. Quindi WordPress offre altre funzioni che ti permettono di usare wp_kses con tag e protocolli consentiti preimpostati, ovvero quelli utilizzati per la convalida di post e commenti:

  • wp_kses_post ()
  • wp_kses_data ()

Le funzioni di cui sopra sono utili per garantire che l'HTML ricevuto dall'utente contenga solo elementi della lista bianca. Una volta fatto ciò, vorremmo anche assicurarci che ogni tag sia bilanciato, ovvero che ogni tag di apertura abbia il tag di chiusura corrispondente. Per questo possiamo usare balanceTags (). Questa funzione accetta due argomenti:

  • soddisfare - Contenuto per filtrare e bilanciare i tag di
  • bilancio di forza - Vero o falso, se forzare il bilanciamento dei tag
 // Contenuto con chiusura mancante  tag $ content = "Clic qui da visitare  wptuts + "; eco balanceTags ($ content, true), // Stampa l'HTML" Clicca qui per visitare  wptuts+ "

I nomi dei file

Se si desidera creare un file in una delle directory del proprio sito Web, è necessario assicurarsi che il nome file sia valido e legale. Dovresti anche assicurarti che il nome file sia unico per quella directory. Per questo WordPress fornisce:

  • sanitize_file_name ($ filename) - disinfetta (o convalida) il nome del file rimuovendo i caratteri che sono illegali nei nomi di file su determinati sistemi operativi o che richiederebbero l'escape sulla riga di comando. Sostituisce gli spazi con trattini e trattini consecutivi con un trattino singolo e rimuove punti, trattini e caratteri di sottolineatura dall'inizio e dalla fine del nome file.
  • wp_unique_filename ($ dir, $ nomefile) - restituisce un unico (per la directory $ dir), nomefile sanitizzato (utilizza sanitize_file_name).

Dati dai campi di testo

Quando si ricevono i dati immessi in un campo di testo, è probabile che si desideri eliminare spazi bianchi, tabulazioni e interruzioni di linea, oltre a rimuovere tutti i tag. Per questo WordPress fornisce sanitize_text_field ().

chiavi

WordPress fornisce anche sanitize_key. Questa è una funzione molto generica (e talvolta utile). Semplicemente assicura che la variabile restituita contenga solo caratteri alfa minuscole, trattini e caratteri di sottolineatura.


Sanificazione dei dati

Mentre la convalida riguarda la garanzia che i dati siano validi: la sanitizzazione dei dati consiste nel farcela sicuro. Mentre alcune delle funzioni di convalida di cui sopra possono essere utili per assicurarsi che i dati siano sicuri - in generale, non è sufficiente. Anche i dati "validi" potrebbero non essere sicuri in determinati contesti.


Regola n. 4: rendere i dati sicuri riguarda il contesto

Semplicemente non puoi chiedere "Come faccio a rendere sicuri questi dati?". Invece dovresti chiedere, "Come faccio a rendere sicuri questi dati per utilizzarlo in X".

Per illustrare questo punto, supponiamo di avere un widget con un'area di testo in cui si intende consentire all'utente di inserire del codice HTML. Supponiamo che poi entrino:

  Ciao mondo

Questo è perfettamente valido e sicuro, HTML - tuttavia quando si fa clic su Salva, scopriamo che il testo è saltato fuori dalla textarea. Il codice HTML non è sicuro come valore per l'area di testo:

Ciò che è sicuro da usare in un contesto, non è necessariamente sicuro in un altro. Ogni volta che si utilizzano o si visualizzano dati, è necessario tenere presente quali forme di igienizzazione devono essere eseguite per rendere sicuro l'utilizzo di tali dati. Ecco perché WordPress offre spesso diverse funzioni per lo stesso contenuto, ad esempio:

Tutti eseguono l'igienizzazione necessaria per un particolare contesto e, se li stai utilizzando, dovresti assicurarti di utilizzare quello corretto. A volte, però, dovremo eseguire la nostra sanitizzazione, spesso perché abbiamo un input personalizzato oltre il titolo standard, il permalink, il contenuto ecc. Che WordPress gestisce per noi.

Escaping HTML

Quando stampi le variabili sulla pagina, dobbiamo essere consapevoli di come il browser le interpreterà. Consideriamo il seguente esempio:

 

supporre $ title = . Piuttosto che visualizzare l'HTML

In effetti, se lo fai, dovresti quasi certamente usarlo wp_localize_script () - che gestisce la sanitizzazione per te. (Se qualcuno può pensare a un motivo per cui potrebbe essere necessario utilizzare il metodo precedente, mi piacerebbe sentirlo).

Tuttavia, per rendere sicuro l'esempio precedente, è possibile utilizzare ESC_JS funzione:

 

Escaping Textarea

Quando si visualizza il contenuto in una textarea, esc_html non è sufficiente perché non raddoppia le entità. Per esempio:

 testo grassetto'?> 

$ var stampato nella textarea apparirà come:

 testo grassetto

Piuttosto che codificare anche il & come & nel tag.

Per questo WordPress fornisce esc_textarea, che è quasi identico a esc_html, ma raddoppia le entità codificate. Essenzialmente è poco più di un involucro per htmlspecialchars. In questo esempio:

 testo grassetto'?> 

Antispambot

La visualizzazione di indirizzi e-mail sul tuo sito Web li rende inclini a raccogliere e-mail. Un metodo semplice è quello di mascherare l'indirizzo e-mail. WordPress fornisce antispambot, che codifica parti casuali dell'indirizzo e-mail nelle loro entità HTML (e equivalenti esadecimali se $ mailto = 1). Su ogni pagina caricare la codifica dovrebbe essere diversa e mentre l'indirizzo restituito viene visualizzato correttamente nel browser, dovrebbe apparire come gobbledygook agli spambots. La funzione accetta due argomenti:

  • e-mail - l'indirizzo per offuscare
  • mailto - 1 o 0 (1 se si utilizza il protocollo mailto in un tag link)
 $ email = "[email protected]"; $ email = sanitize_email ($ email); echo '' .antispambot ($ email). ' ';

Stringhe di query

Se si desidera aggiungere (o rimuovere) variabili da una stringa di query (questo è molto utile se si desidera consentire agli utenti di selezionare un ordine per i propri messaggi), il modo più sicuro e semplice è quello di utilizzare add_query_arg e remove_query_arg. Queste funzioni gestiscono l'escape necessario per gli argomenti e i relativi valori da utilizzare nell'URL.

add_query_arg accetta due argomenti:

  • parametri di query - un array associativo di parametri -> valori
  • url - l'URL per aggiungere i parametri e i loro valori a. Se omesso, viene utilizzato l'URL della pagina corrente

remove_query_arg accetta anche due argomenti, il primo è un array di parametri da rimuovere, il secondo è come sopra.

 // Se siamo su www.example.com/wp-admin/edit.php?post_type=book $ query_params = array ('page' => 'my-bage'); $ url = add_query_arg ($ query_params); // impostare $ url come: // www.example.com/wp-admin/edit.php?post_type=book&page=my-page

Validazione e sanificazione

Come accennato in precedenza, la sterilizzazione non ha molto senso senza un contesto - quindi è quasi inutile sanificare i dati durante la scrittura nel database. Spesso, è necessario archiviare i dati nel formato raw in ogni caso e, in ogni caso, la regola n. 1 stabilisce che dovremmo sempre disinfettare l'output.

La convalida dei dati, d'altra parte, dovrebbe essere eseguita non appena viene ricevuta e prima che sia scritta nel database. L'idea è che i dati "non validi" debbano essere corretti automaticamente o essere contrassegnati per i dati, e solo i dati validi dovrebbero essere dati al database.

Detto questo, si consiglia di eseguire anche la convalida quando vengono visualizzati i dati. In effetti, a volte, la "convalida" garantisce anche la sicurezza dei dati. Ma qui la priorità è sulla sicurezza e dovresti evitare una convalida eccessiva che verrebbe eseguita su ogni caricamento della pagina (il file wp_kses_ * le funzioni, ad esempio, sono molto costose da eseguire).


Escaping del database

Quando si usano funzioni come get_posts o classi come WP_Query e WP_User_Query, WordPress si prende cura della necessaria sanitizzazione nell'interrogazione del database. Tuttavia, quando si recuperano dati da una tabella personalizzata, o comunque si esegue una query SQL diretta sul database, la corretta sanitizzazione dipende da voi. WordPress, tuttavia, fornisce una classe utile, il $ wpdb classe, che aiuta con l'escape di query SQL.

Consideriamo questo fondamentale 'SELEZIONARE'comando, dove $ età e $ firstname sono variabili che memorizzano un'età e un nome che stiamo interrogando:

 SELECT * WHERE age = "$ age" AND firstname = '$ firstname'

Non siamo sfuggiti a queste variabili, quindi potrebbero essere iniettati potenzialmente ulteriori comandi. Prendendo a prestito l'esempio di xkcd dall'alto:

 $ età = 14; $ firstname = "Robert"; Studenti DROP TABLE; "; $ sql = "SELECT * WHERE age =" $ age "AND firstname = '$ firstname';"; $ risultati = $ wpdb-> query

Funzionerà come il comando (s):

 SELECT * WHERE age = "14" AND firstname = 'Robert'; DROP TABLE Studenti; ';

E cancella la nostra intera tabella Studenti.

Per evitare ciò, possiamo usare il $ Wpdb-> preparare metodo. Questo accetta due parametri:

  • Il comando SQL come una stringa, in cui le variabili stringa vengono sostituite dal segnaposto %S e i numeri decimali sono sostituiti dal segnaposto % d e galleggia vicino % f
  • Un array di valori per i segnaposto di cui sopra, nell'ordine in cui appaiono nella query

In questo esempio:

 $ età = 14; $ firstname = "Robert"; Studenti DROP TABLE; "; $ sql = $ wpdb-> prepare ('SELECT * WHERE età =% d AND firstname =% s;', array ($ age, $ firstname)); $ risultati = $ wpdb-> get_results ($ sql);

La query SQL con escape ($ sql in questo esempio) può quindi essere utilizzato con uno dei seguenti metodi:

  • $ Wpdb-> get_row ($ sql)
  • $ Wpdb-> get_var ($ sql)
  • $ Wpdb-> get_results ($ sql)
  • $ Wpdb-> get_col ($ sql)
  • $ Wpdb-> query ($ sql)

Inserimento e aggiornamento dei dati

Per l'inserimento o l'aggiornamento dei dati, WordPress rende la vita ancora più semplice fornendo il $ Wpdb-> inserire () e $ Wpdb-> update () metodi.

Il $ Wpdb-> inserire () il metodo accetta tre argomenti:

  • Nome della tabella - il nome del tavolo
  • Dati - matrice di dati da inserire come colonne> coppie di valori
  • formati - serie di formati per i valori corrispondenti ('%S''% d' o'% f')
 $ età = 14; $ firstname = "Robert"; Studenti DROP TABLE; "; $ wpdb-> insert ('Studenti', array ('firstname' => $ firstname, 'age' => $ age), array ('% s', '% d'));

Il $ Wpdb-> update () il metodo accetta cinque argomenti:

  • Nome della tabella - il nome del tavolo
  • Dati - matrice di dati da aggiornare come coppie colonna-> valore
  • Dove - matrice di dati da abbinare a coppie colonna-> valore
  • Formato dei dati - matrice di formati per i corrispondenti valori di dati
  • Dove Format - matrice di formati per i corrispondenti valori "dove"
 // Aggiorna Robert '; DROP TABLE Studenti; a Bobby $ oldname = "Robert"; Studenti DROP TABLE; "; $ newname = "Bobby"; $ wpdb-> update ('Studenti', array ('firstname' => $ newname), array ('firstname' => $ oldname), array ('% s'), array ('% s'));

Sia il $ Wpdb-> inserire () e il $ Wpdb-> update () i metodi eseguono tutte le operazioni di sanitizzazione necessarie per la scrittura nel database.

Mi piace dichiarazioni

Perché il $ Wpdb-> preparare usi del metodo % per distinguere i segnaposto, occorre prestare attenzione quando si usa il % jolly in istruzioni SQL LIKE. Il Codice suggerisce di sfuggirgli con un secondo %. In alternativa puoi sfuggire al termine da cercare like_escape e quindi aggiungere il carattere jolly % se del caso, prima di includerlo nella query utilizzando il metodo di preparazione. Per esempio:

 $ Età = 14; $ firstname = "Robert"; Studenti DROP TABLE; "; SELECT * WHERE age = $ age (firstname LIKE '% $ firstname%');

Sarebbe stato reso sicuro con:

 $ Età = 14; $ firstname = "Robert"; Studenti DROP TABLE; "; SELECT * WHERE age = $ age AND (firstname LIKE '% $ firstname%'); $ query = $ wpdb-> prepare ('SELECT * WHERE age =% d AND (firstname LIKE% s);', array ($ age, '%'. like_escape ($ firstname). '%'));

Sommario

Questo non è un elenco esauriente delle funzioni disponibili per la convalida e l'igienizzazione, ma dovrebbe coprire la maggior parte dei casi d'uso. Molte di queste (e altre) funzioni possono essere trovate in /wp-includes/formatting.php e consiglio vivamente di scavare nel codice di base e dare un'occhiata a come il core di WordPress convalida e sanifica i dati.

Hai trovato questo articolo utile? Avete ulteriori suggerimenti sulle migliori pratiche per la convalida e la sanificazione dei dati in WordPress? Fateci sapere nei commenti qui sotto.