Fare htmlspecialchars e mysql_real_escape_string mantenere il mio codice PHP sicuro da iniezione?

StackOverflow https://stackoverflow.com/questions/110575

Domanda

Prima di oggi, una domanda è stato chiesto in merito convalida dell'input di strategie di web apps.

La risposta in alto, al momento della scrittura, suggerisce in PHP usando solo htmlspecialchars e mysql_real_escape_string.

La mia domanda è:Questo è sempre abbastanza?C'è di più si dovrebbe sapere?Dove fare queste funzioni abbattere?

È stato utile?

Soluzione

Quando si tratta di query su database, provare sempre a utilizzare query con parametri preparate. Le librerie mysqli e PDO supportano questo. Questo è infinitamente più sicuro rispetto all'utilizzo delle funzioni di escape come mysql_real_escape_string.

Sì, id è effettivamente solo una funzione di escape della stringa. Non è un proiettile magico. Tutto ciò che farà è sfuggire ai caratteri pericolosi in modo che possano essere sicuri da usare in una singola stringa di query. Tuttavia, se non disinfetti in anticipo i tuoi input, allora sarai vulnerabile a determinati vettori di attacco.

Immagina il seguente SQL:

$result = "SELECT fields FROM table WHERE id = ".mysql_real_escape_string($_POST['id']);

Dovresti essere in grado di vedere che questo è vulnerabile allo sfruttamento.
Immagina che il parametro 1 OR 1=1 contenesse il vettore di attacco comune:

1 OR 1=1

Non ci sono caratteri rischiosi da codificare, quindi passerà direttamente attraverso il filtro di escape. Lasciandoci:

SELECT fields FROM table WHERE id= 1 OR 1=1

Che è un adorabile vettore di iniezione SQL e consentirebbe all'attaccante di restituire tutte le righe. O

1 or is_admin=1 order by id limit 1

che produce

SELECT fields FROM table WHERE id=1 or is_admin=1 order by id limit 1

Che consente all'attaccante di restituire i dettagli del primo amministratore in questo esempio completamente fittizio.

Sebbene queste funzioni siano utili, devono essere utilizzate con cura. È necessario assicurarsi che tutti gli input Web siano convalidati in una certa misura. In questo caso, vediamo che possiamo essere sfruttati perché non abbiamo verificato che una variabile che stavamo usando come numero fosse effettivamente numerica. In PHP dovresti ampiamente utilizzare un insieme di funzioni per verificare che gli input siano numeri interi, float, alfanumerici ecc. Ma quando si tratta di SQL, fai attenzione al valore dell'istruzione preparata. Il codice sopra riportato sarebbe stato sicuro se si fosse trattato di un'istruzione preparata poiché le funzioni del database avrebbero saputo che htmlspecialchars() non è un valore letterale valido.

Come per javascript:alert(document.cookie). Questo è un campo minato a parte.

C'è un vero problema in PHP in quanto ha un'intera selezione di diverse funzioni di escape correlate all'html e nessuna guida chiara su quali funzioni facciano esattamente.

In primo luogo, se ti trovi all'interno di un tag HTML, sei davvero nei guai. Guarda

echo '<img src= "' . htmlspecialchars($_GET['imagesrc']) . '" />';

Siamo già dentro un tag HTML, quindi non abbiamo bisogno di < o > fare qualcosa di pericoloso. Il nostro vettore di attacco potrebbe essere htmlspecialchars

Ora l'HTML risultante sembra

<img src= "javascript:alert(document.cookie)" />

L'attacco finisce dritto.

Peggiora. Perché? perché htmlspecialchars($string) (quando chiamato in questo modo) codifica solo virgolette doppie e non singole. Quindi se avessimo

echo "<img src= '" . htmlspecialchars($_GET['imagesrc']) . ". />";

Il nostro malvagio attaccante ora può iniettare parametri completamente nuovi

pic.png' onclick='location.href=xxx' onmouseover='...

ci dà

<img src='pic.png' onclick='location.href=xxx' onmouseover='...' />

In questi casi, non esiste un proiettile magico, devi solo santizzare l'input tu stesso. Se provi a filtrare i personaggi cattivi, fallirai sicuramente. Prendi un approccio da whitelist e lascia passare solo i caratteri che sono buoni. Guarda il Cheat sheet XSS per esempi su come possono essere diversi vettori

Anche se usi <=> al di fuori dei tag HTML, sei ancora vulnerabile ai vettori di attacco charset multi-byte.

Il più efficace che puoi essere è usare la combinazione di mb_convert_encoding e htmlentities come segue.

$str = mb_convert_encoding($str, 'UTF-8', 'UTF-8');
$str = htmlentities($str, ENT_QUOTES, 'UTF-8');

Anche questo lascia IE6 vulnerabile, a causa del modo in cui gestisce UTF. Tuttavia, potresti ricorrere a una codifica più limitata, come ISO-8859-1, fino a quando l'utilizzo di IE6 non diminuisce.

Per uno studio più approfondito sui problemi multibyte, vedere https://stackoverflow.com/a/12118602/1820

Altri suggerimenti

Oltre all'ottima risposta di Cheekysoft:

  • Sì, ti terranno al sicuro, ma solo se utilizzati in modo assolutamente corretto. Usali in modo errato e sarai comunque vulnerabile e potresti avere altri problemi (ad esempio corruzione dei dati)
  • Utilizzare invece query con parametri (come indicato sopra). Puoi usarli attraverso ad es. DOP o tramite un wrapper come PEAR DB
  • Assicurati che magic_quotes_gpc e magic_quotes_runtime siano sempre spenti e non vengano mai accesi accidentalmente, nemmeno per un breve periodo. Si tratta di un tentativo iniziale e profondamente fuorviato da parte degli sviluppatori di PHP di prevenire problemi di sicurezza (che distruggono i dati)

Non esiste davvero un proiettile d'argento per impedire l'iniezione HTML (ad esempio scripting cross site), ma potresti essere in grado di raggiungerlo più facilmente se stai usando una libreria o un sistema di template per produrre HTML. Leggi la documentazione per quello su come sfuggire alle cose in modo appropriato.

In HTML, le cose devono essere sfuggite in modo diverso a seconda del contesto. Ciò è particolarmente vero per le stringhe inserite in Javascript.

Mi sarebbe sicuramente d'accordo con il precedente post, ma ho una piccola cosa da aggiungere in risposta a Cheekysoft risposta, in particolare:

Quando si tratta di query di database, sempre provare ad utilizzare il preparato parametrizzare le query.Il mysqli e DOP librerie di supporto.Questo è infinitamente più sicuro rispetto all'utilizzo di fuga funzioni come mysql_real_escape_string.

Sì, è mysql_real_escape_string efficacemente solo una stringa di escape funzione.Non è una bacchetta magica.Tutto quello che fare è fuggire pericoloso i caratteri in modo che possano essere sicuro per l'uso in una singola stringa di query.Tuttavia, se non igienizzare il tuo ingressi in anticipo, allora si sarà vulnerabile a certi vettori di attacco.

Immaginate la seguente SQL:

$risultato = "SELEZIONARE i campi DALLA tabella WHERE id = ".mysql_real_escape_string($_POST['id']);

Si dovrebbe essere in grado di vedere che questo è vulnerabile a sfruttare.Immaginate l'id parametro contiene l'attacco più comuni vettore:

1 O 1=1

Non c'è rischioso caratteri per codificare, in modo passerà direttamente attraverso la fuoriuscita di filtro.Lasciando noi:

SELEZIONARE i campi FROM tabella WHERE id = 1 O 1=1

Ho codificato un piccolo e veloce funzione che ho messo nel mio database di classe che striscia fuori tutto ciò che non è un numero.Utilizza la funzione preg_replace, quindi non c'è prob un po ' più ottimizzato in funzione, ma funziona in un pizzico...

function Numbers($input) {
  $input = preg_replace("/[^0-9]/","", $input);
  if($input == '') $input = 0;
  return $input;
}

Così, invece di utilizzare

$risultato = "SELECT campi FROM tabella WHERE id = ".mysqlrealescapestring("1 O 1=1");

Vorrei utilizzare

$risultato = "SELECT campi FROM tabella WHERE id = ".Numeri("1 O 1=1");

e sarebbe tranquillamente eseguire la query

SELEZIONARE i campi FROM tabella WHERE id = 111

Certo, che appena smesso di visualizzare la riga corretta, ma non credo che sia un grosso problema per chi sta cercando di iniettare sql nel tuo sito ;)

Un pezzo importante di questo puzzle sono i contesti. Qualcuno che invia & Quot; 1 OPPURE 1 = 1 & Quot; poiché l'ID non è un problema se si citano tutti gli argomenti della query:

SELECT fields FROM table WHERE id='".mysql_real_escape_string($_GET['id'])."'"

Che risulta in:

SELECT fields FROM table WHERE id='1 OR 1=1'

che è inefficace. Dato che stai sfuggendo alla stringa, l'input non può uscire dal contesto della stringa. Ho provato questo fino alla versione 5.0.45 di MySQL e l'uso di un contesto di stringa per una colonna intera non causa alcun problema.

$result = "SELECT fields FROM table WHERE id = ".(INT) $_GET['id'];

Funziona bene, ancora meglio su sistemi a 64 bit. Fai attenzione alle limitazioni dei tuoi sistemi nell'affrontare grandi numeri, ma per gli ID di database funziona ben il 99% delle volte.

Dovresti usare anche una singola funzione / metodo per pulire i tuoi valori. Anche se questa funzione è solo un wrapper per mysql_real_escape_string (). Perché? Perché un giorno quando viene trovato un exploit al tuo metodo preferito di pulizia dei dati devi solo aggiornarlo in un posto, piuttosto che trovare e sostituire a livello di sistema.

perché, oh PERCHÉ, dovresti non includere citazioni sull'input dell'utente nella tua dichiarazione sql? sembra abbastanza sciocco non farlo! includendo le virgolette nell'istruzione sql verrebbe visualizzato " 1 o 1 = 1 " un tentativo infruttuoso, no?

così ora, dirai, " cosa succede se l'utente include un preventivo (o virgolette doppie) nell'input? "

beh, soluzione semplice per questo: basta rimuovere le virgolette inserite dall'utente. ad es .: input =~ s/'//g;. ora, mi sembra comunque, che l'input dell'utente sarebbe protetto ...

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top