Come validare correttamente i dati da $_GET o $_REQUEST utilizzando le funzioni di WordPress?
Sto lavorando a un plugin che richiede la manipolazione dinamica dell'output dei contenuti. Questo dipende esclusivamente dalla variabile $_GET
corrente o dalla variabile $_REQUEST
.
A seconda di come è impostata la variabile, verrà chiamato un determinato metodo della classe per gestire la richiesta dell'utente e visualizzare il contenuto appropriato.
Sono pienamente consapevole della pagina Validazione dei Dati sul Codex di WordPress, tuttavia non sono sicuro di quale sia l'approccio migliore per il mio scenario, o per qualsiasi scenario di sanitizzazione delle variabili $_GET
o $_REQUEST
.
Come posso sanitizzare utilizzando le funzioni di WordPress per una variabile $_GET
o $_REQUEST
quando si tratta di una stringa che verrà confrontata per chiamare un metodo specifico di una classe?
Questo codice potrebbe essere sfruttato o fallire nelle seguenti condizioni?:
public function display_admin_page(){
if(is_admin() && isset($_GET['page'])){
global $content;
$page = sanitize_title($_GET['page']);
$method_name = 'page_'.str_replace('-', '_', $page);
if(method_exists('content', $method_name)){
// Visualizza la pagina richiesta dalla classe content
$thePage = $content->$method_name();
} else{
$thePage = $content->error(404);
}
echo $thePage;
}
}

WordPress non fornisce funzioni specifiche per la validazione dei dati nei SUPERGLOBAL.
Utilizzo la funzione PHP filter_input e poi la proteggo come farei con qualsiasi variabile non attendibile.
$url = filter_input( INPUT_GET, 'some_query_string', FILTER_VALIDATE_URL );
echo '<a href="'. esc_url( $url ). '">Cliccami</a>';
La funzione filter_input di PHP accetta:

Per il tuo esempio specifico:
Hai sanificato i dati $_GET appropriatamente (anche se io userei sanitize_key
invece di sanitize_title
-- non c'è molta differenza, ma sanitize_title
è pensato per l'uso negli URL).
La funzione method_exists
restituirà true anche per i metodi privati e protetti, quindi se un utente cerca di chiamare un metodo privato o protetto, fallirà senza arrivare al 404. (A meno che il metodo display_admin_page
non sia nella stessa classe.)
Questo ci porta alla principale potenziale vulnerabilità: chiunque può forzare l'esecuzione di qualsiasi metodo pubblico nella tua classe. Se possibile, è sempre meglio specificare una whitelist di ciò che può essere accettato. In questo modo potresti validare con qualcosa come:
if ( !in_array( $_GET['page'], array( 'accepted_method', 'another_accepted_method' ) ) )
$content->error(404);

Potresti gentilmente elaborare ulteriormente la teoria del potenziale exploit?

Certo, intendo dire che è qualcosa che devi semplicemente analizzare a fondo. Ogni metodo pubblico nella tua classe può essere forzato a essere eseguito da chiunque in qualsiasi momento. Questo non è automaticamente un exploit, ma è una considerazione da fare. C'è un metodo nella tua classe che elimina dal tuo database? C'è un metodo che stampa le password dei tuoi utenti? Aggiungerai mai altri metodi di cui dovrai preoccuparti? Ecc.

Consiglio di utilizzare mysql_real_escape_string($_GET)
su qualsiasi richiesta GET. È una funzionalità PHP molto potente.
Successivamente puoi utilizzare str_replace()
per sostituire qualsiasi carattere indesiderato.
AGGIORNAMENTO 2023:
esc_sql()
è la soluzione perfetta.

La sanificazione di $_GET
è piuttosto specifica al contesto. Dipende dal valore che desideri e da come vuoi che venga validato.
Non esiste una risposta universale a questa domanda. È molto specifica al contesto. Ad esempio, potresti scrivere una funzione che rimuove tutti i tag e gli slash dall'input, il che è molto sicuro, ma cosa succede se volessi salvare un tag p? Nessun problema lì. La famiglia di funzioni wp_kses() è uno studio interessante, ma non è una grande soluzione, poiché tiene conto del contesto, del livello dell'utente e altro ancora. Ad esempio, come amministratore puoi salvare JavaScript nel titolo e nel contenuto del post, ma con un ruolo inferiore non puoi.
Se il valore è una quantità nota, puoi anche verificare se in_array( $array_valid_strings )
ed essere sicuro al riguardo.
Detto questo, ci sono diversi gradi di sanificazione, quindi è importante tenere a mente il tuo obiettivo finale. Consulterei questa lista e troverei la funzione o la combinazione di funzioni che si adatta alle tue esigenze. Sono specificamente le funzioni sanitize_ quelle che dovrebbero essere utilizzate qui, non esc_. La sanificazione e l'escape continuano a essere confusi...
Nel mio caso utilizzerò sanitize_text_field() perché sanifica una stringa dall'input dell'utente o dal database.
- Verifica la presenza di UTF-8 non valido,
- Converte i singoli caratteri < in entità
- Rimuove tutti i tag
- Rimuove le interruzioni di riga, le tabulazioni e gli spazi extra
- Rimuove gli ottetti
Buona fortuna :).
P.S. Questa risposta cita le prospettive di tre diversi sviluppatori (Josh, Michal, Kevin).
