Domanda

Se l'input dell'utente viene inserito senza modifiche in una query SQL, l'applicazione diventa vulnerabile a SQL Injection, come nell'esempio seguente:

$unsafe_variable = $_POST['user_input']; 

mysql_query("INSERT INTO `table` (`column`) VALUES ('$unsafe_variable')");

Questo perché l'utente può inserire qualcosa di simile value'); DROP TABLE table;--, e la query diventa:

INSERT INTO `table` (`column`) VALUES('value'); DROP TABLE table;--')

Cosa si può fare per evitare che ciò accada?

È stato utile?

Soluzione

Utilizzare istruzioni preparate e query con parametri. Si tratta di istruzioni SQL inviate e analizzate dal server del database separatamente da qualsiasi parametro.In questo modo è impossibile per un utente malintenzionato iniettare SQL dannoso.

Fondamentalmente hai due opzioni per raggiungere questo obiettivo:

  1. Utilizzando DOP (per qualsiasi driver di database supportato):

    $stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name');
    
    $stmt->execute(array('name' => $name));
    
    foreach ($stmt as $row) {
        // do something with $row
    }
    
  2. Utilizzando MySQLi (per MySQL):

    $stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?');
    $stmt->bind_param('s', $name); // 's' specifies the variable type => 'string'
    
    $stmt->execute();
    
    $result = $stmt->get_result();
    while ($row = $result->fetch_assoc()) {
        // do something with $row
    }
    

Se ti connetti a un database diverso da MySQL, esiste una seconda opzione specifica del driver a cui puoi fare riferimento (ad es. pg_prepare() E pg_execute() per PostgreSQL).La DOP è l'opzione universale.

Configurazione corretta della connessione

Si noti che durante l'utilizzo PDO per accedere a un database MySQL vero le dichiarazioni preparate sono non utilizzato per impostazione predefinita.Per risolvere questo problema è necessario disabilitare l'emulazione delle istruzioni preparate.Un esempio di creazione di una connessione utilizzando PDO è:

$dbConnection = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'pass');

$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

Nell'esempio sopra la modalità errore non è strettamente necessaria, ma si consiglia di aggiungerlo.In questo modo lo script non si fermerà con a Fatal Error quando qualcosa va storto.E offre allo sviluppatore la possibilità di farlo catch eventuali errori che sono thrown come PDOExceptionS.

Cosa è obbligatorio, tuttavia, è il primo setAttribute() linea, che dice a PDO di disabilitare le istruzioni preparate emulate e di utilizzarle vero dichiarazioni preparate.Ciò garantisce che l'istruzione e i valori non vengano analizzati da PHP prima di inviarli al server MySQL (non dando a un possibile utente malintenzionato alcuna possibilità di iniettare SQL dannoso).

Sebbene sia possibile impostare il charset nelle opzioni del costruttore, è importante notare che le versioni "precedenti" di PHP (< ​​5.3.6) ignorato silenziosamente il parametro charset nel DSN.

Spiegazione

Ciò che succede è che l'istruzione SQL a cui passi prepare viene analizzato e compilato dal server del database.Specificando i parametri (a ? o un parametro denominato come :name nell'esempio sopra) dici al motore del database dove vuoi filtrare.Poi quando chiami execute, l'istruzione preparata viene combinata con i valori dei parametri specificati.

La cosa importante qui è che i valori dei parametri siano combinati con l'istruzione compilata, non con una stringa SQL.L'SQL injection funziona inducendo lo script a includere stringhe dannose quando crea SQL da inviare al database.Quindi, inviando l'SQL effettivo separatamente dai parametri, limiti il ​​rischio di ritrovarti con qualcosa che non volevi.Tutti i parametri inviati quando si utilizza un'istruzione preparata verranno trattati semplicemente come stringhe (sebbene il motore del database possa eseguire alcune ottimizzazioni in modo che anche i parametri possano finire come numeri, ovviamente).Nell'esempio sopra, se il $name la variabile contiene 'Sarah'; DELETE FROM employees il risultato sarebbe semplicemente una ricerca della stringa "'Sarah'; DELETE FROM employees", e non ti ritroverai un tavolo vuoto.

Un altro vantaggio derivante dall'utilizzo delle istruzioni preparate è che se esegui la stessa istruzione più volte nella stessa sessione, verrà analizzata e compilata solo una volta, offrendoti un aumento di velocità.

Oh, e poiché hai chiesto come farlo per un inserto, ecco un esempio (usando PDO):

$preparedStatement = $db->prepare('INSERT INTO table (column) VALUES (:column)');

$preparedStatement->execute(array('column' => $unsafeValue));

È possibile utilizzare istruzioni preparate per query dinamiche?

Sebbene sia comunque possibile utilizzare istruzioni preparate per i parametri della query, la struttura della query dinamica stessa non può essere parametrizzata e alcune funzionalità della query non possono essere parametrizzate.

Per questi scenari specifici, la cosa migliore da fare è utilizzare un filtro whitelist che limiti i valori possibili.

// Value whitelist
// $dir can only be 'DESC' otherwise it will be 'ASC'
if (empty($dir) || $dir !== 'DESC') {
   $dir = 'ASC';
}

Altri suggerimenti

Avviso deprecato:Il codice di esempio di questa risposta (come il codice di esempio della domanda) utilizza PHP MySQL estensione, deprecata in PHP 5.5.0 e rimossa completamente in PHP 7.0.0.

Avviso di sicurezza:Questa risposta non è in linea con le migliori pratiche di sicurezza. L'escape non è adeguato per impedire l'SQL injection, utilizzo dichiarazioni preparate Invece.Utilizza la strategia descritta di seguito a tuo rischio e pericolo.(Anche, mysql_real_escape_string() è stato rimosso in PHP 7.)

Se stai utilizzando una versione recente di PHP, il file mysql_real_escape_string l'opzione descritta di seguito non sarà più disponibile (tuttavia mysqli::escape_string è un equivalente moderno).In questi giorni il mysql_real_escape_string l'opzione avrebbe senso solo per il codice legacy su una vecchia versione di PHP.


Hai due opzioni: sfuggire ai caratteri speciali nel tuo unsafe_variable, o utilizzando una query con parametri.Entrambi ti proteggerebbero dall'iniezione SQL.La query con parametri è considerata la pratica migliore, ma richiederà il passaggio a un'estensione MySQL più recente in PHP prima di poterla utilizzare.

Copriremo prima la corda a impatto inferiore che fuoriesce da una.

//Connect

$unsafe_variable = $_POST["user-input"];
$safe_variable = mysql_real_escape_string($unsafe_variable);

mysql_query("INSERT INTO table (column) VALUES ('" . $safe_variable . "')");

//Disconnect

Vedi anche i dettagli del mysql_real_escape_string funzione.

Per utilizzare la query con parametri, è necessario utilizzare MySQLi piuttosto che il MySQL funzioni.Per riscrivere il tuo esempio, avremmo bisogno di qualcosa di simile al seguente.

<?php
    $mysqli = new mysqli("server", "username", "password", "database_name");

    // TODO - Check that connection was successful.

    $unsafe_variable = $_POST["user-input"];

    $stmt = $mysqli->prepare("INSERT INTO table (column) VALUES (?)");

    // TODO check that $stmt creation succeeded

    // "s" means the database expects a string
    $stmt->bind_param("s", $unsafe_variable);

    $stmt->execute();

    $stmt->close();

    $mysqli->close();
?>

La funzione chiave su cui vorresti leggere sarebbe mysqli::prepare.

Inoltre, come altri hanno suggerito, potresti trovare utile/più facile aumentare un livello di astrazione con qualcosa di simile DOP.

Tieni presente che il caso che hai chiesto è abbastanza semplice e che casi più complessi potrebbero richiedere approcci più complessi.In particolare:

  • Se desideri modificare la struttura dell'SQL in base all'input dell'utente, le query parametrizzate non saranno di aiuto e l'escape richiesto non è coperto da mysql_real_escape_string.In questo tipo di caso, sarebbe meglio passare l'input dell'utente attraverso una whitelist per garantire che siano consentiti solo valori "sicuri".
  • Se utilizzi numeri interi dall'input dell'utente in una condizione e prendi il file mysql_real_escape_string approccio, soffrirai del problema descritto da Polinomio nei commenti qui sotto.Questo caso è più complicato perché gli interi non sarebbero racchiusi tra virgolette, quindi potresti risolverlo verificando che l'input dell'utente contenga solo cifre.
  • Probabilmente ci sono altri casi di cui non sono a conoscenza.Potresti trovare Questo è una risorsa utile su alcuni dei problemi più sottili che puoi incontrare.

Ogni risposta qui copre solo una parte del problema.In effetti, ci sono quattro diverse parti della query che possiamo aggiungere dinamicamente:-

  • una stringa
  • un numero
  • un identificatore
  • una parola chiave della sintassi.

E le dichiarazioni preparate riguardano solo due di essi.

Ma a volte dobbiamo rendere la nostra query ancora più dinamica, aggiungendo anche operatori o identificatori.Quindi, avremo bisogno di diverse tecniche di protezione.

In generale, tale approccio di protezione si basa su lista bianca.

In questo caso, ogni parametro dinamico dovrebbe essere codificato nello script e scelto da quel set.Ad esempio, per eseguire l'ordinamento dinamico:

$orders  = array("name", "price", "qty"); // Field names
$key     = array_search($_GET['sort'], $orders)); // See if we have such a name
$orderby = $orders[$key]; // If not, first one will be set automatically. smart enuf :)
$query   = "SELECT * FROM `table` ORDER BY $orderby"; // Value is safe

Tuttavia, esiste un altro modo per proteggere gli identificatori: l'escape.Finché hai un identificatore tra virgolette, puoi sfuggire ai backtick all'interno raddoppiandoli.

Come passo ulteriore, possiamo prendere in prestito l'idea davvero brillante di utilizzare qualche segnaposto (un proxy per rappresentare il valore effettivo nella query) dalle istruzioni preparate e inventare un segnaposto di altro tipo: un segnaposto identificativo.

Quindi, per farla breve:è un segnaposto, non discorso preparato può essere considerata come una soluzione miracolosa.

Pertanto, una raccomandazione generale può essere formulata comeFinché aggiungi parti dinamiche alla query utilizzando i segnaposto (e questi segnaposto vengono elaborati correttamente, ovviamente), puoi essere sicuro che la tua query è sicura.

Tuttavia, c'è un problema con le parole chiave della sintassi SQL (come AND, DESC e simili), ma in questo caso la white list sembra l'unico approccio.

Aggiornamento

Sebbene esista un accordo generale sulle migliori pratiche relative alla protezione dall'iniezione SQL, esistono ancora molte cattive pratiche. E alcuni di essi sono troppo profondamente radicati nella mente degli utenti PHP.Ad esempio, proprio in questa pagina sono presenti (anche se invisibili alla maggior parte dei visitatori) più di 80 risposte cancellate - tutti rimossi dalla community a causa della cattiva qualità o della promozione di pratiche cattive e obsolete.Peggio ancora, alcune delle risposte negative non vengono cancellate, ma anzi prosperano.

Per esempio, lì(1) sono(2) ancora(3) molti(4) risposte(5), includendo il seconda risposta più votata suggerendo l'escape manuale delle stringhe: un approccio obsoleto che si è dimostrato insicuro.

Oppure c'è una risposta leggermente migliore che suggerisce semplicemente un altro metodo di formattazione delle stringhe e lo vanta addirittura come la panacea definitiva.Anche se ovviamente non lo è.Questo metodo non è migliore della normale formattazione delle stringhe, ma presenta tutti i suoi svantaggi:è applicabile solo alle stringhe e, come qualsiasi altra formattazione manuale, è essenzialmente una misura facoltativa, non obbligatoria, soggetta a errori umani di qualsiasi tipo.

Penso che tutto questo sia dovuto a un'antichissima superstizione, sostenuta da tali autorità OWASP O il manuale PHP, che proclama l'uguaglianza tra ciò che "fugge" e la protezione dalle SQL injection.

Indipendentemente da ciò che il manuale PHP ha detto per anni, *_escape_string non rende in alcun modo i dati sicuri e non è mai stato previsto che lo facesse.Oltre ad essere inutile per qualsiasi parte SQL diversa dalla stringa, l'escape manuale è sbagliato, perché è manuale e non automatizzato.

E OWASP rende le cose ancora peggiori, insistendo sulla fuga input dell'utente che è una totale sciocchezza:non dovrebbero esserci parole del genere nel contesto della protezione dall'iniezione.Ogni variabile è potenzialmente pericolosa, indipendentemente dalla fonte!O, in altre parole, ogni variabile deve essere formattata correttamente per essere inserita in una query, indipendentemente dalla fonte.È la destinazione che conta.Nel momento in cui uno sviluppatore inizia a separare le pecore dalle capre (pensando se qualche variabile particolare è "sicura" o meno) fa il primo passo verso il disastro.Per non parlare del fatto che anche la formulazione suggerisce una fuga di massa nel punto di ingresso, somigliando proprio alla funzione delle virgolette magiche - già disprezzata, deprecata e rimossa.

Quindi, a differenza di qualunque cosa "sfugga", le dichiarazioni preparate È la misura che effettivamente protegge dall'SQL injection (quando applicabile).

Se non sei ancora convinto, ecco una spiegazione passo passo che ho scritto, La guida per autostoppisti alla prevenzione dell'SQL Injection, dove ho spiegato tutte queste questioni in dettaglio e ho anche compilato una sezione interamente dedicata alle cattive pratiche e alla loro divulgazione.

Consiglierei l'uso DOP (PHP Data Objects) per eseguire query SQL con parametri.

Ciò non solo protegge dall'SQL injection, ma accelera anche le query.

E utilizzando PDO anziché mysql_, mysqli_, E pgsql_ funzioni, rendi la tua app un po' più astratta dal database, nel raro caso in cui devi cambiare provider di database.

Utilizzo PDO e domande preparate.

($conn è un PDO oggetto)

$stmt = $conn->prepare("INSERT INTO tbl VALUES(:id, :name)");
$stmt->bindValue(':id', $id);
$stmt->bindValue(':name', $name);
$stmt->execute();

Come puoi vedere, le persone suggeriscono di utilizzare al massimo affermazioni preparate.Non è sbagliato, ma quando la tua query viene eseguita solo una volta per processo, ci sarebbe una leggera penalità in termini di prestazioni.

Stavo affrontando questo problema, ma penso di averlo risolto molto modo sofisticato: il modo utilizzato dagli hacker per evitare l'uso delle virgolette.L'ho usato insieme alle istruzioni preparate emulate.Lo uso per prevenire Tutto tipi di possibili attacchi SQL injection.

Il mio approccio:

  • Se prevedi che l'input sia intero, assicurati che lo sia Veramente numero intero.In un linguaggio di tipo variabile come PHP è questo molto importante.Puoi utilizzare ad esempio questa soluzione molto semplice ma potente: sprintf("SELECT 1,2,3 FROM table WHERE 4 = %u", $input);

  • Se ti aspetti qualcos'altro da integer maledizione.Se lo esagoni, sfuggirai perfettamente a tutti gli input.In C/C++ c'è una funzione chiamata mysql_hex_string(), in PHP puoi usare bin2hex().

    Non preoccuparti che la stringa di escape avrà una dimensione pari a 2 volte la sua lunghezza originale perché anche se usi mysql_real_escape_string, PHP deve allocare la stessa capacità ((2*input_length)+1), che è lo stesso.

  • Questo metodo esadecimale viene spesso utilizzato quando si trasferiscono dati binari, ma non vedo alcun motivo per cui non utilizzarlo su tutti i dati per prevenire attacchi SQL injection.Tieni presente che devi anteporre i dati con 0x oppure utilizzare la funzione MySQL UNHEX Invece.

Quindi, ad esempio, la query:

SELECT password FROM users WHERE name = 'root'

Diventerà:

SELECT password FROM users WHERE name = 0x726f6f74

O

SELECT password FROM users WHERE name = UNHEX('726f6f74')

Hex è la fuga perfetta.Nessun modo per iniettare.

Differenza tra la funzione UNHEX e il prefisso 0x

C'è stata qualche discussione nei commenti, quindi voglio finalmente renderlo chiaro.Questi due approcci sono molto simili, ma sono leggermente diversi in alcuni aspetti:

Il prefisso ** 0x** può essere utilizzato solo per colonne di dati come char, varchar, testo, blocco, binario, ecc.
Inoltre, il suo utilizzo è un po' complicato se si sta per inserire una stringa vuota.Dovrai sostituirlo completamente con '', oppure riceverai un errore.

UNHEX() funziona su Qualunque colonna;non devi preoccuparti della stringa vuota.


I metodi esadecimali vengono spesso utilizzati come attacchi

Tieni presente che questo metodo esadecimale viene spesso utilizzato come attacco SQL injection in cui gli interi sono proprio come stringhe e vengono sfuggiti solo con mysql_real_escape_string.Quindi puoi evitare l'uso delle virgolette.

Ad esempio, se fai qualcosa del genere:

"SELECT title FROM article WHERE id = " . mysql_real_escape_string($_GET["id"])

un attacco può iniettarti molto facilmente.Considera il seguente codice iniettato restituito dal tuo script:

SELEZIONARE ...DOVE id = -1 unione seleziona tutti nome_tabella da information_schema.tables

e ora estrai semplicemente la struttura della tabella:

SELEZIONARE ...WHERE id = -1 unione tutti seleziona nome_colonna da schema_informazioni.colonna dove nome_tabella = 0x61727469636c65

E poi seleziona semplicemente i dati che desideri.Non è bello?

Ma se il codificatore di un sito iniettabile lo eseguisse, non sarebbe possibile alcuna iniezione perché la query sarebbe simile a questa: SELECT ... WHERE id = UNHEX('2d312075...3635')

Avviso deprecato:Il codice di esempio di questa risposta (come il codice di esempio della domanda) utilizza PHP MySQL estensione, deprecata in PHP 5.5.0 e rimossa completamente in PHP 7.0.0.

Avviso di sicurezza:Questa risposta non è in linea con le migliori pratiche di sicurezza. L'escape non è adeguato per impedire l'SQL injection, utilizzo dichiarazioni preparate Invece.Utilizza la strategia descritta di seguito a tuo rischio e pericolo.(Anche, mysql_real_escape_string() è stato rimosso in PHP 7.)

IMPORTANTE

Il modo migliore per prevenire SQL Injection è utilizzare Dichiarazioni preparate invece di scappare, COME la risposta accettata dimostra.

Ci sono biblioteche come Aura.Sql E EasyDB che consentono agli sviluppatori di utilizzare più facilmente le istruzioni preparate.Per saperne di più sul perché le dichiarazioni preparate sono migliori interrompere l'iniezione SQL, fare riferimento a Questo mysql_real_escape_string() circonvallazione E recentemente corrette le vulnerabilità Unicode SQL Injection in WordPress.

Prevenzione delle iniezioni - mysql_real_escape_string()

PHP ha una funzione appositamente creata per prevenire questi attacchi.Tutto quello che devi fare è usare la bocca di una funzione, mysql_real_escape_string.

mysql_real_escape_string prende una stringa che verrà utilizzata in una query MySQL e restituisce la stessa stringa con tutti i tentativi di SQL injection sfuggiti in modo sicuro.Fondamentalmente, sostituirà le virgolette fastidiose (') che un utente potrebbe inserire con un sostituto sicuro per MySQL, una virgoletta con escape \'.

NOTA: devi essere connesso al database per utilizzare questa funzione!

// Connettiti a MySQL

$name_bad = "' OR 1'"; 

$name_bad = mysql_real_escape_string($name_bad);

$query_bad = "SELECT * FROM customers WHERE username = '$name_bad'";
echo "Escaped Bad Injection: <br />" . $query_bad . "<br />";


$name_evil = "'; DELETE FROM customers WHERE 1 or username = '"; 

$name_evil = mysql_real_escape_string($name_evil);

$query_evil = "SELECT * FROM customers WHERE username = '$name_evil'";
echo "Escaped Evil Injection: <br />" . $query_evil;

Puoi trovare maggiori dettagli in MySQL - Prevenzione dell'iniezione SQL.

Avviso deprecato:Il codice di esempio di questa risposta (come il codice di esempio della domanda) utilizza PHP MySQL estensione, deprecata in PHP 5.5.0 e rimossa completamente in PHP 7.0.0.

Avviso di sicurezza:Questa risposta non è in linea con le migliori pratiche di sicurezza. L'escape non è adeguato per impedire l'SQL injection, utilizzo dichiarazioni preparate Invece.Utilizza la strategia descritta di seguito a tuo rischio e pericolo.(Anche, mysql_real_escape_string() è stato rimosso in PHP 7.)

Potresti fare qualcosa di semplice come questo:

$safe_variable = mysqli_real_escape_string($_POST["user-input"], $dbConnection);
mysqli_query("INSERT INTO table (column) VALUES ('" . $safe_variable . "')");

Questo non risolverà tutti i problemi, ma è un ottimo trampolino di lancio.Ho tralasciato elementi ovvi come il controllo dell'esistenza della variabile, del formato (numeri, lettere, ecc.).

Qualunque cosa usi, assicurati di controllare che il tuo input non sia già stato alterato magic_quotes o qualche altra spazzatura ben intenzionata e, se necessario, esaminala stripslashes o qualunque cosa per igienizzarlo.

Avviso deprecato:Il codice di esempio di questa risposta (come il codice di esempio della domanda) utilizza PHP MySQL estensione, deprecata in PHP 5.5.0 e rimossa completamente in PHP 7.0.0.

Avviso di sicurezza:Questa risposta non è in linea con le migliori pratiche di sicurezza. L'escape non è adeguato per impedire l'SQL injection, utilizzo dichiarazioni preparate Invece.Utilizza la strategia descritta di seguito a tuo rischio e pericolo.(Anche, mysql_real_escape_string() è stato rimosso in PHP 7.)

La query parametrizzata E la convalida dell'input sono la strada da percorrere.Tuttavia, esistono molti scenari in cui può verificarsi l'iniezione SQL mysql_real_escape_string() è stato usato.

Questi esempi sono vulnerabili all'iniezione SQL:

$offset = isset($_GET['o']) ? $_GET['o'] : 0;
$offset = mysql_real_escape_string($offset);
RunQuery("SELECT userid, username FROM sql_injection_test LIMIT $offset, 10");

O

$order = isset($_GET['o']) ? $_GET['o'] : 'userid';
$order = mysql_real_escape_string($order);
RunQuery("SELECT userid, username FROM sql_injection_test ORDER BY `$order`");

In entrambi i casi, non è possibile utilizzare ' per proteggere l'incapsulamento.

Fonte: L'inaspettata SQL Injection (quando l'escape non è sufficiente)

A mio parere, il modo migliore per prevenire in generale l'SQL injection nella tua applicazione PHP (o in qualsiasi applicazione web, del resto) è pensare all'architettura della tua applicazione.Se l’unico modo per proteggersi dall’SQL injection è ricordarsi di utilizzare un metodo o una funzione speciale che fa la cosa giusta ogni volta che parli con il database, stai sbagliando.In questo modo, è solo questione di tempo finché non ti dimentichi di formattare correttamente la query ad un certo punto del codice.

Adottando il modello MVC e un framework simile TortaPHP O CodeIgniter è probabilmente la strada giusta da percorrere:Compiti comuni come la creazione di query di database sicure sono stati risolti e implementati centralmente in tali framework.Ti aiutano a organizzare la tua applicazione web in modo sensato e ti fanno pensare più al caricamento e al salvataggio di oggetti che alla costruzione sicura di singole query SQL.

Sono favorevole procedura di archiviazione (MySQL supporta le procedure memorizzate dalla versione 5.0) dal punto di vista della sicurezza - i vantaggi sono -

  1. La maggior parte dei database (inclusi MySQL) consentono di limitare l'accesso degli utenti all'esecuzione delle procedure memorizzate.Il controllo capillare degli accessi di sicurezza è utile per prevenire l'escalation degli attacchi ai privilegi.Ciò impedisce alle applicazioni compromesse di eseguire SQL direttamente sul database.
  2. Astraono la query SQL grezza dall'applicazione in modo che siano disponibili per l'applicazione meno informazioni sulla struttura del database.Ciò rende più difficile per le persone comprendere la struttura sottostante del database e progettare attacchi adeguati.
  3. Accettano solo parametri, quindi sono presenti i vantaggi delle query con parametri.Ovviamente, secondo l'IMO, devi comunque ripulire il tuo input, soprattutto se stai utilizzando SQL dinamico all'interno della procedura memorizzata.

Gli svantaggi sono -

  1. Esse (le procedure memorizzate) sono difficili da mantenere e tendono a moltiplicarsi molto rapidamente.Ciò rende la loro gestione un problema.
  2. Non sono molto adatti per le query dinamiche: se sono costruiti per accettare codice dinamico come parametri, molti vantaggi vengono annullati.

Esistono molti modi per prevenire SQL injection e altri hack SQL.Puoi trovarlo facilmente su Internet (Cerca con Google).Ovviamente La DOP è una delle buone soluzioni. Ma vorrei suggerirti qualche buona prevenzione dei collegamenti da SQL Injection.

Cos'è l'SQL injection e come prevenirla

Manuale PHP per SQL injection

Spiegazione Microsoft di SQL injection e prevenzione in PHP

e qualche altro simile Prevenire l'SQL injection con MySQL e PHP

Ora, perché è necessario impedire alla query di eseguire l'iniezione SQL?

Vorrei farti sapere:Perché proviamo a prevenire l'SQL injection con un breve esempio di seguito:

Query per la corrispondenza dell'autenticazione di accesso:

$query="select * from users where email='".$_POST['email']."' and password='".$_POST['password']."' ";

Ora, se qualcuno (un hacker) mette

$_POST['email']= admin@emali.com' OR '1=1

e password qualsiasi cosa....

La query verrà analizzata nel sistema solo fino a:

$query="select * from users where email='admin@emali.com' OR '1=1';

L'altra parte verrà scartata.Allora, cosa succederà?Un utente non autorizzato (hacker) potrà accedere come amministratore senza avere la sua password.Ora può fare tutto ciò che può fare l'amministratore/e-mail.Vedi, è molto pericoloso se l'SQL injection non viene impedita.

Penso che se qualcuno vuole usare PHP e MySQL o qualche altro server dataBase:

  1. Pensa all'apprendimento DOP (PHP Data Objects) – è un livello di accesso al database che fornisce un metodo uniforme di accesso a più database.
  2. Pensa all'apprendimento MySQLi
  3. Utilizza funzioni PHP native come: strip_tags, mysql_real_escape_string o se variabile numerica, solo (int)$foo.Maggiori informazioni sul tipo di variabili in PHP Qui.Se utilizzi librerie come PDO o MySQLi, utilizza sempre DOP::quote() E mysqli_real_escape_string().

Esempi di biblioteche:

---- DOP

----- Nessun segnaposto: pronto per l'SQL injection! È cattivo

$request = $pdoConnection->("INSERT INTO parents (name, addr, city) values ($name, $addr, $city)");

----- Segnaposto senza nome

$request = $pdoConnection->("INSERT INTO parents (name, addr, city) values (?, ?, ?);

----- Segnaposto con nome

$request = $pdoConnection->("INSERT INTO parents (name, addr, city) value (:name, :addr, :city)");

--- MySQLi

$request = $mysqliConnection->prepare('
       SELECT * FROM trainers
       WHERE name = ?
       AND email = ?
       AND last_login > ?');

    $query->bind_param('first_param', 'second_param', $mail, time() - 3600);
    $query->execute();

PS:

PDO vince questa battaglia con facilità.Con il supporto per dodici diversi driver di database e parametri denominati, possiamo ignorare la piccola perdita di prestazioni e abituarci alla sua API.Dal punto di vista della sicurezza, entrambi sono al sicuro fintanto che lo sviluppatore li usa nel modo in cui dovrebbero essere utilizzati

Ma mentre sia PDO che Mysqli sono abbastanza veloci, Mysqli si comporta in modo insignificante più veloce nei benchmark-~ 2,5% per dichiarazioni non preparate e ~ 6,5% per quelle preparate.

E per favore testa ogni query sul tuo database: è un modo migliore per prevenire l'iniezione.

Se possibile, esegui il cast dei tipi dei tuoi parametri.Ma funziona solo su tipi semplici come int, bool e float.

$unsafe_variable = $_POST['user_id'];

$safe_variable = (int)$unsafe_variable ;

mysqli_query($conn, "INSERT INTO table (column) VALUES ('" . $safe_variable . "')");

Se vuoi sfruttare i motori di cache, ad esempio Redis O Memcached, forse DALMP potrebbe essere una scelta.Si usa puro MySQLi.Controllare questo: Livello di astrazione del database DALMP per MySQL utilizzando PHP.

Inoltre, puoi "preparare" i tuoi argomenti prima di preparare la query in modo da poter creare query dinamiche e alla fine avere una query di istruzioni completamente preparata. Livello di astrazione del database DALMP per MySQL utilizzando PHP.

Per coloro che non sono sicuri di come utilizzare PDO (proveniente da mysql_ funzioni), ho creato a involucro DOP molto, molto semplice questo è un singolo file.Esiste per mostrare quanto sia facile fare tutte le cose comuni che le applicazioni devono fare.Funziona con PostgreSQL, MySQL e SQLite.

Insomma, leggilo mentre leggi il manuale per vedere come utilizzare le funzioni PDO nella vita reale per semplificare la memorizzazione e il recupero dei valori nel formato Voi Volere.

Voglio una singola colonna

$count = DB::column('SELECT COUNT(*) FROM `user`);

Voglio un risultato array (chiave => valore) (cioèper creare una casella di selezione)

$pairs = DB::pairs('SELECT `id`, `username` FROM `user`);

Voglio un risultato a riga singola

$user = DB::row('SELECT * FROM `user` WHERE `id` = ?', array($user_id));

Voglio una serie di risultati

$banned_users = DB::fetch('SELECT * FROM `user` WHERE `banned` = ?', array(TRUE));

Usando questa funzione PHP mysql_escape_string() puoi ottenere una buona prevenzione in modo veloce.

Per esempio:

SELECT * FROM users WHERE name = '".mysql_escape_string($name_from_html_form)."'

mysql_escape_string — Esegue l'escape di una stringa da utilizzare in una mysql_query

Per una maggiore prevenzione, puoi aggiungere alla fine ...

wHERE 1=1   or  LIMIT 1

Alla fine ottieni:

SELECT * FROM users WHERE name = '".mysql_escape_string($name_from_html_form)."' LIMIT 1

Alcune linee guida per l'escape dei caratteri speciali nelle istruzioni SQL.

Non utilizzare MySQL, questa estensione è deprecata, utilizzare MySQLi O DOP.

MySQLi

Per eseguire manualmente l'escape dei caratteri speciali in una stringa è possibile utilizzare il comando mysqli_real_escape_string funzione.La funzione non funzionerà correttamente a meno che non venga impostato il set di caratteri corretto con mysqli_set_charset.

Esempio:

$mysqli = new mysqli( 'host', 'user', 'password', 'database' );
$mysqli->set_charset( 'charset');

$string = $mysqli->real_escape_string( $string );
$mysqli->query( "INSERT INTO table (column) VALUES ('$string')" );

Per l'escape automatico dei valori con istruzioni preparate, utilizzare mysqli_prepare, E mysqli_stmt_bind_param dove devono essere forniti i tipi per le variabili di associazione corrispondenti per una conversione appropriata:

Esempio:

$stmt = $mysqli->prepare( "INSERT INTO table ( column1, column2 ) VALUES (?,?)" );

$stmt->bind_param( "is", $integer, $string );

$stmt->execute();

Non importa se usi istruzioni preparate o mysqli_real_escape_string, devi sempre conoscere il tipo di dati di input con cui stai lavorando.

Quindi, se usi un'istruzione preparata, devi specificare i tipi di variabili per la funzione mysqli_stmt_bind_param.

E l'uso di mysqli_real_escape_string serve, come dice il nome, a eseguire l'escape dei caratteri speciali in una stringa, quindi non renderà sicuri gli interi.Lo scopo di questa funzione è impedire la rottura delle stringhe nelle istruzioni SQL e il danno che ciò potrebbe causare al database.mysqli_real_escape_string è una funzione utile se utilizzata correttamente, soprattutto se combinata con sprintf.

Esempio:

$string = "x' OR name LIKE '%John%";
$integer = '5 OR id != 0';

$query = sprintf( "SELECT id, email, pass, name FROM members WHERE email ='%s' AND id = %d", $mysqli->real_escape_string( $string ), $integer );

echo $query;
// SELECT id, email, pass, name FROM members WHERE email ='x\' OR name LIKE \'%John%' AND id = 5

$integer = '99999999999999999999';
$query = sprintf( "SELECT id, email, pass, name FROM members WHERE email ='%s' AND id = %d", $mysqli->real_escape_string( $string ), $integer );

echo $query;
// SELECT id, email, pass, name FROM members WHERE email ='x\' OR name LIKE \'%John%' AND id = 2147483647

La semplice alternativa a questo problema potrebbe essere risolta concedendo i permessi appropriati nel database stesso.Per esempio:se stai utilizzando un database MySQL, accedi al database tramite il terminale o l'interfaccia utente fornita e segui semplicemente questo comando:

 GRANT SELECT, INSERT, DELETE ON database TO username@'localhost' IDENTIFIED BY 'password';

Ciò limiterà l'utente a rimanere confinato solo con la query specificata.Rimuovi l'autorizzazione di eliminazione e quindi i dati non verranno mai eliminati dalla query attivata dalla pagina PHP.La seconda cosa da fare è svuotare i privilegi in modo che MySQL aggiorni le autorizzazioni e gli aggiornamenti.

FLUSH PRIVILEGES; 

ulteriori informazioni su sciacquone.

Per visualizzare i privilegi attuali dell'utente, eseguire la query seguente.

select * from mysql.user where User='username';

Impara di più riguardo CONCESSIONE.

Avviso di sicurezza:Questa risposta non è in linea con le migliori pratiche di sicurezza. L'escape non è adeguato per impedire l'SQL injection, utilizzo dichiarazioni preparate Invece.Utilizza la strategia descritta di seguito a tuo rischio e pericolo.(Anche, mysql_real_escape_string() è stato rimosso in PHP 7.)

Avviso deprecato:L'estensione mysql è attualmente deprecata.si consiglia di utilizzare il DOP

Utilizzo tre modi diversi per impedire che la mia applicazione Web sia vulnerabile all'iniezione SQL.

  1. Utilizzo di mysql_real_escape_string(), che è una funzione predefinita in PHP, e questo codice aggiunge barre rovesciate ai seguenti caratteri: \x00, \n, \r, \, ', " E \x1a.Passa i valori di input come parametri per ridurre al minimo la possibilità di SQL injection.
  2. Il modo più avanzato è utilizzare i PDO.

Spero che questo ti aiuterà.

Considera la seguente query:

$iId = mysql_real_escape_string("1 OR 1=1"); $sSql = "SELECT * FROM table WHERE id = $iId";

mysql_real_escape_string() non proteggerà qui.Se usi virgolette singole (' ') attorno alle variabili all'interno della tua query è ciò che ti protegge da questo.Ecco una soluzione di seguito per questo:

$iId = (int) mysql_real_escape_string("1 OR 1=1"); $sSql = "SELECT * FROM table WHERE id = $iId";

Questo domanda ha alcune buone risposte a riguardo.

Suggerisco che l'utilizzo di PDO sia l'opzione migliore.

Modificare:

mysql_real_escape_string() è deprecato a partire da PHP 5.5.0.Utilizzare mysqli o PDO.

Un'alternativa a mysql_real_escape_string() è

string mysqli_real_escape_string ( mysqli $link , string $escapestr )

Esempio:

$iId = $mysqli->real_escape_string("1 OR 1=1");
$mysqli->query("SELECT * FROM table WHERE id = $iId");

Per quanto riguarda molte risposte utili, spero di aggiungere alcuni valori a questo thread.L'iniezione SQL è un attacco che può essere eseguito tramite input dell'utente (input compilati dall'utente e quindi utilizzati all'interno delle query). I modelli di iniezione SQL sono la sintassi corretta delle query mentre possiamo chiamarla:query sbagliate per ragioni sbagliate, presumiamo che potrebbe esserci una persona cattiva che tenta di ottenere informazioni segrete (aggirando il controllo degli accessi) che influiscono sui tre principi di sicurezza (riservatezza, integrità, disponibilità).

Ora, il nostro punto è prevenire minacce alla sicurezza come attacchi SQL injection, la domanda che pone (Come prevenire l'attacco SQL injection utilizzando PHP), essere più realistici, filtrare i dati o cancellare i dati di input è il caso quando si utilizzano dati immessi dall'utente all'interno di tali query, l'utilizzo di PHP o qualsiasi altro linguaggio di programmazione non è il caso, o come raccomandato da più persone di utilizzare la tecnologia moderna come istruzioni preparate o qualsiasi altro strumento che attualmente supporta la prevenzione dell'iniezione SQL, ritieni che questi strumenti non siano più disponibili?Come proteggi la tua applicazione?

Il mio approccio contro l'SQL injection è:cancellare i dati immessi dall'utente prima di inviarli al database (prima di utilizzarli all'interno di qualsiasi query).

Filtraggio dei dati per (conversione di dati non sicuri in dati sicuri)Considera che DOP E MySQLi non disponibile, come puoi proteggere la tua richiesta?Mi costringi ad usarli?Che dire di altri linguaggi diversi da PHP?Preferisco fornire idee generali in quanto può essere utilizzato per confini più ampi e non solo per un linguaggio specifico.

  1. Utente SQL (limitazione dei privilegi utente):le operazioni SQL più comuni sono (SELECT, UPDATE, INSERT), quindi perché dare il privilegio UPDATE a un utente che non lo richiede?Per esempio login e pagine di ricerca stai utilizzando solo SELECT, quindi perché utilizzare utenti DB in queste pagine con privilegi elevati?REGOLA:non creare un utente del database per tutti i privilegi, per tutte le operazioni SQL è possibile creare il proprio schema come (deluser, selectuser, updateuser) come nomi utente per un facile utilizzo.

Vedere Principio del privilegio minimo

  1. Filtraggio dei dati:prima di creare qualsiasi query, l'input dell'utente deve essere convalidato e filtrato, per i programmatori è importante definire alcune proprietà per ciascuna variabile di input dell'utente:tipo di dati, modello di dati e lunghezza dei dati.un campo che è un numero compreso tra (x e y) deve essere convalidato esattamente utilizzando la regola esatta, per un campo che è una stringa (testo):pattern è il caso, ad esempio, il nome utente deve contenere solo alcuni caratteri, diciamo [a-zA-Z0-9_-.] la lunghezza varia tra (x e n) dove x e n (interi, x <=n ).Regola:creare filtri esatti e regole di convalida è la migliore pratica per me.

  2. Utilizza altri strumenti:Qui, concorderò anche con te sul fatto che l'istruzione preparata (query parametrizzata) e le procedure memorizzate, lo svantaggio qui è che questi metodi richiedono competenze avanzate che non esistono per la maggior parte degli utenti, l'idea di base qui è distinguere tra la query SQL e i dati utilizzato all'interno, entrambi gli approcci possono essere utilizzati anche con dati non sicuri, poiché i dati immessi dall'utente qui non aggiungono nulla alla query originale come (qualsiasi o x=x).Per ulteriori informazioni, leggere Foglio informativo sulla prevenzione dell'iniezione SQL OWASP.

Ora, se sei un utente avanzato, inizia a utilizzare questa difesa come preferisci, ma, per i principianti, se non riescono a implementare rapidamente la procedura memorizzata e a preparare l'istruzione, è meglio filtrare i dati di input il più possibile.

Consideriamo infine che l'utente invii questo testo qui sotto invece di inserire il suo nome utente:

[1] UNION SELECT IF(SUBSTRING(Password,1,1)='2',BENCHMARK(100000,SHA1(1)),0) User,Password FROM mysql.user WHERE User = 'root'

Questo input può essere controllato in anticipo senza alcuna istruzione preparata e procedure memorizzate, ma per essere sicuri, il loro utilizzo inizia dopo il filtraggio e la convalida dei dati utente.

L'ultimo punto è rilevare comportamenti inaspettati che richiedono maggiore impegno e complessità;non è consigliato per le normali applicazioni web.Il comportamento imprevisto nell'input utente precedente è SELECT, UNION, IF, SUBSTRING, BENCHMARK, SHA, root una volta rilevate queste parole, è possibile evitare l'input.

AGGIORNAMENTO1:

Un utente ha commentato che questo post è inutile, OK!Ecco cosa OWASP.ORG fornito:

Difese primarie:

Opzione 1:Utilizzo di istruzioni preparate (query parametrizzate)
Opzione 2:Utilizzo di procedure memorizzate
Opzione n. 3:Escape di tutti gli input forniti dall'utente

Difese aggiuntive:

Applicare anche:Privilegio minimo
Esegui anche:Convalida dell'input della lista bianca

Come forse saprai, rivendicare un articolo dovrebbe essere supportato da un argomento valido, almeno un riferimento!Altrimenti è considerato un attacco e una cattiva pretesa!

Aggiornamento2:

Dal manuale PHP, PHP:Dichiarazioni preparate - Manuale:

Escape e SQL injection

Le variabili associate verranno automaticamente sottoposte a escape dal server.Il server inserisce i loro valori sfuggiti nei luoghi appropriati nel modello di istruzione prima dell'esecuzione.Un suggerimento deve essere fornito al server per il tipo di variabile vincolata, per creare una conversione appropriata.Vedi la funzione mysqli_stmt_bind_param () per ulteriori informazioni.

La fuga automatica dei valori all'interno del server è talvolta considerata una funzione di sicurezza per prevenire l'iniezione di SQL.Lo stesso grado di sicurezza può essere raggiunto con dichiarazioni non preparate se i valori di input vengono sfuggiti correttamente.

Aggiornamento3:

Ho creato casi di test per sapere come PDO e MySQLi inviano la query al server MySQL quando si utilizza l'istruzione preparata:

DOP:

$user = "''1''"; //Malicious keyword
$sql = 'SELECT * FROM awa_user WHERE userame =:username';
$sth = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$sth->execute(array(':username' => $user));

Registro delle query:

    189 Query SELECT * FROM awa_user WHERE userame ='\'\'1\'\''
    189 Quit

MySQL:

$stmt = $mysqli->prepare("SELECT * FROM awa_user WHERE username =?")) {
$stmt->bind_param("s", $user);
$user = "''1''";
$stmt->execute();

Registro delle query:

    188 Prepare   SELECT * FROM awa_user WHERE username =?
    188 Execute   SELECT * FROM awa_user WHERE username ='\'\'1\'\''
    188 Quit

È chiaro che tra i dati sfugge anche un comunicato preparato, nient'altro.

Come accennato anche nella dichiarazione di cui sopra The automatic escaping of values within the server is sometimes considered a security feature to prevent SQL injection. The same degree of security can be achieved with non-prepared statements, if input values are escaped correctly, pertanto, ciò dimostra che la convalida dei dati come intval() è una buona idea inserire valori interi prima di inviare qualsiasi query, inoltre, è possibile prevenire dati utente dannosi prima di inviare la query approccio corretto e valido.

Per favore vedi questa domanda per maggiori dettagli: PDO invia query non elaborate a MySQL mentre Mysqli invia query preparate, entrambi producono lo stesso risultato

Riferimenti:

  1. Foglio informativo sull'iniezione SQL
  2. SQL Injection
  3. Informazioni di sicurezza
  4. Principi di sicurezza
  5. Convalida dei dati

Un modo semplice sarebbe utilizzare un framework PHP come CodeIgniter O Laravel che hanno funzionalità integrate come il filtraggio e la registrazione attiva in modo da non doverti preoccupare di queste sfumature.

** Avvertimento:l'approccio descritto in questa risposta si applica solo a scenari molto specifici e non è sicuro poiché gli attacchi SQL injection non si basano solo sulla capacità di iniettare X=Y.**

Se gli aggressori stanno tentando di hackerare il modulo tramite PHP $_GET variabile o con la stringa di query dell'URL, sarai in grado di rilevarli se non sono sicuri.

RewriteCond %{QUERY_STRING} ([0-9]+)=([0-9]+)
RewriteRule ^(.*) ^/track.php

Perché 1=1, 2=2, 1=2, 2=1, 1+1=2, eccetera...sono le domande più comuni rivolte a un database SQL da un utente malintenzionato.Forse viene utilizzato anche da molte applicazioni di hacking.

Ma devi stare attento a non riscrivere una query sicura dal tuo sito.Il codice sopra ti dà un suggerimento da riscrivere o reindirizzare (dipende da te) quella stringa di query dinamica specifica dell'hacking in una pagina che memorizzerà quella dell'aggressore indirizzo IP, o ANCHE I LORO COOKIE, cronologia, browser o qualsiasi altra informazione sensibile, in modo da poterli gestire in seguito vietando il loro account o contattando le autorità.

Ci sono così tante risposte per PHP e MySQL, ma ecco il codice per PHP e Oracle per prevenire l'iniezione SQL e l'uso regolare dei driver oci8:

$conn = oci_connect($username, $password, $connection_string);
$stmt = oci_parse($conn, 'UPDATE table SET field = :xx WHERE ID = 123');
oci_bind_by_name($stmt, ':xx', $fieldval);
oci_execute($stmt);

Una buona idea è usare un file 'mappatore relazionale di oggetti' Piace Idiorma:

$user = ORM::for_table('user')
->where_equal('username', 'j4mie')
->find_one();

$user->first_name = 'Jamie';
$user->save();

$tweets = ORM::for_table('tweet')
    ->select('tweet.*')
    ->join('user', array(
        'user.id', '=', 'tweet.user_id'
    ))
    ->where_equal('user.username', 'j4mie')
    ->find_many();

foreach ($tweets as $tweet) {
    echo $tweet->text;
}

Non solo ti salva dalle iniezioni SQL ma anche dagli errori di sintassi!Supporta anche raccolte di modelli con concatenamento di metodi per filtrare o applicare azioni a più risultati contemporaneamente e più connessioni.

Avviso deprecato:Il codice di esempio di questa risposta (come il codice di esempio della domanda) utilizza PHP MySQL estensione, deprecata in PHP 5.5.0 e rimossa completamente in PHP 7.0.0.

Avviso di sicurezza:Questa risposta non è in linea con le migliori pratiche di sicurezza. L'escape non è adeguato per impedire l'SQL injection, utilizzo dichiarazioni preparate Invece.Utilizza la strategia descritta di seguito a tuo rischio e pericolo.(Anche, mysql_real_escape_string() è stato rimosso in PHP 7.)

Utilizzando DOP E MYSQLi è una buona pratica per prevenire SQL injection, ma se vuoi davvero lavorare con funzioni e query MySQL, sarebbe meglio usare

mysql_real_escape_string

$unsafe_variable = mysql_real_escape_string($_POST['user_input']);

Esistono più capacità per impedirlo:come identificare: se l'input è una stringa, un numero, un carattere o un array, ci sono così tante funzioni integrate per rilevarlo.Inoltre, sarebbe meglio utilizzare queste funzioni per controllare i dati di input.

è_stringa

$unsafe_variable = (is_string($_POST['user_input']) ? $_POST['user_input'] : '');

è_numerico

$unsafe_variable = (is_numeric($_POST['user_input']) ? $_POST['user_input'] : '');

Ed è molto meglio usare queste funzioni per controllare i dati di input mysql_real_escape_string.

Ho scritto questa piccola funzione diversi anni fa:

function sqlvprintf($query, $args)
{
    global $DB_LINK;
    $ctr = 0;
    ensureConnection(); // Connect to database if not connected already.
    $values = array();
    foreach ($args as $value)
    {
        if (is_string($value))
        {
            $value = "'" . mysqli_real_escape_string($DB_LINK, $value) . "'";
        }
        else if (is_null($value))
        {
            $value = 'NULL';
        }
        else if (!is_int($value) && !is_float($value))
        {
            die('Only numeric, string, array and NULL arguments allowed in a query. Argument '.($ctr+1).' is not a basic type, it\'s type is '. gettype($value). '.');
        }
        $values[] = $value;
        $ctr++;
    }
    $query = preg_replace_callback(
        '/{(\\d+)}/', 
        function($match) use ($values)
        {
            if (isset($values[$match[1]]))
            {
                return $values[$match[1]];
            }
            else
            {
                return $match[0];
            }
        },
        $query
    );
    return $query;
}

function runEscapedQuery($preparedQuery /*, ...*/)
{
    $params = array_slice(func_get_args(), 1);
    $results = runQuery(sqlvprintf($preparedQuery, $params)); // Run query and fetch results.   
    return $results;
}

Ciò consente di eseguire istruzioni in un String.Format C#-ish di una riga come:

runEscapedQuery("INSERT INTO Whatever (id, foo, bar) VALUES ({0}, {1}, {2})", $numericVar, $stringVar1, $stringVar2);

Sfugge considerando il tipo di variabile.Se provi a parametrizzare la tabella e i nomi delle colonne, fallirebbe poiché mette ogni stringa tra virgolette che è una sintassi non valida.

AGGIORNAMENTO DELLA SICUREZZA:Il precedente str_replace la versione consentiva iniezioni aggiungendo {#} token ai dati dell'utente.Questo preg_replace_callback La versione non causa problemi se la sostituzione contiene questi token.

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