So che PreparedStatements evita / previene SQL Injection. Come lo fa? La query del modulo finale che viene costruita utilizzando PreparedStatements sarà una stringa o altrimenti?
So che PreparedStatements evita / previene SQL Injection. Come lo fa? La query del modulo finale che viene costruita utilizzando PreparedStatements sarà una stringa o altrimenti?
Risposte:
Il problema con SQL injection è che un input dell'utente viene utilizzato come parte dell'istruzione SQL. Utilizzando le istruzioni preparate è possibile forzare la gestione dell'input dell'utente come contenuto di un parametro (e non come parte del comando SQL).
Ma se non si utilizza l'input dell'utente come parametro per l'istruzione preparata, ma si crea invece il comando SQL unendo le stringhe, si è comunque vulnerabili alle iniezioni SQL anche quando si utilizzano istruzioni preparate.
Considera due modi per fare la stessa cosa:
PreparedStatement stmt = conn.createStatement("INSERT INTO students VALUES('" + user + "')");
stmt.execute();
O
PreparedStatement stmt = conn.prepareStatement("INSERT INTO student VALUES(?)");
stmt.setString(1, user);
stmt.execute();
Se "utente" proveniva dall'input dell'utente e l'input dell'utente era
Robert'); DROP TABLE students; --
Quindi, in primo luogo, verresti lavato. Nel secondo, saresti al sicuro e Little Bobby Tables sarebbe registrato per la tua scuola.
Per capire come PreparedStatement impedisce SQL Injection, è necessario comprendere le fasi di esecuzione di SQL Query.
1. Fase di compilazione. 2. Fase di esecuzione.
Ogni volta che il motore di SQL Server riceve una query, deve passare attraverso le seguenti fasi,
Fase di analisi e normalizzazione: in questa fase viene verificata la sintassi e la semantica della query. Controlla se la tabella di riferimenti e le colonne utilizzate nella query esistono o meno. Ha anche molte altre attività da svolgere, ma non entriamo nei dettagli.
Fase di compilazione: in questa fase, le parole chiave utilizzate nella query come seleziona, da, dove ecc. Vengono convertite in un formato comprensibile dalla macchina. Questa è la fase in cui viene interpretata la query e viene decisa l'azione corrispondente da intraprendere. Ha anche molte altre attività da svolgere, ma non entriamo nei dettagli.
Piano di ottimizzazione della query: in questa fase, viene creato l'albero decisionale per individuare i modi in cui è possibile eseguire la query. Individua il numero di modi in cui la query può essere eseguita e il costo associato a ciascuna modalità di esecuzione della query. Sceglie il piano migliore per eseguire una query.
Cache: il miglior piano selezionato nel piano di ottimizzazione delle query viene archiviato nella cache, in modo che ogni volta che arriva la stessa query la volta successiva, non deve passare nuovamente attraverso la fase 1, la fase 2 e la fase 3. La prossima volta che la query arriverà, verrà controllata direttamente nella cache e prelevata da lì per l'esecuzione.
Fase di esecuzione:
in questa fase, la query fornita viene eseguita ei dati vengono restituiti all'utente come ResultSet
oggetto.
Le PreparedStatement non sono query SQL complete e contengono segnaposto, che in fase di esecuzione vengono sostituiti dai dati forniti dall'utente.
Ogni volta che qualsiasi PreparedStatment contenente segnaposto viene passato al motore di SQL Server, passa attraverso le fasi seguenti
UPDATE user set username =? e password =? WHERE id =?
La query sopra verrà analizzata, compilata con segnaposto come trattamento speciale, ottimizzata e memorizzata nella cache. La query in questa fase è già compilata e convertita in un formato comprensibile dalla macchina. Quindi possiamo dire che la query archiviata nella cache è precompilata e solo i segnaposto devono essere sostituiti con i dati forniti dall'utente.
Ora in fase di esecuzione, quando arrivano i dati forniti dall'utente, la query precompilata viene prelevata dalla cache e i segnaposto vengono sostituiti con i dati forniti dall'utente.
(Ricorda, dopo che i segnaposto sono stati sostituiti con i dati dell'utente, la query finale non viene compilata / interpretata di nuovo e il motore di SQL Server tratta i dati dell'utente come dati puri e non un SQL che deve essere analizzato o compilato di nuovo; questa è la bellezza di PreparedStatement. )
Se la query non deve passare di nuovo attraverso la fase di compilazione, i dati sostituiti sui segnaposto vengono trattati come dati puri e non hanno alcun significato per il motore di SQL Server ed esegue direttamente la query.
Nota: è la fase di compilazione dopo la fase di analisi, che comprende / interpreta la struttura della query e fornisce un comportamento significativo ad essa. In caso di PreparedStatement, la query viene compilata solo una volta e la query compilata memorizzata nella cache viene raccolta continuamente per sostituire i dati dell'utente ed essere eseguita.
A causa della funzionalità di compilazione una tantum di PreparedStatement, è privo di attacchi SQL Injection.
Puoi ottenere una spiegazione dettagliata con un esempio qui: https://javabypatel.blogspot.com/2015/09/how-prepared-statement-in-java-prevents-sql-injection.html
L'SQL utilizzato in PreparedStatement è precompilato nel driver. Da quel momento in poi, i parametri vengono inviati al driver come valori letterali e non parti eseguibili di SQL; quindi nessun SQL può essere iniettato utilizzando un parametro. Un altro effetto collaterale vantaggioso di PreparedStatements (precompilazione + invio solo di parametri) è il miglioramento delle prestazioni quando si esegue l'istruzione più volte anche con valori diversi per i parametri (supponendo che il driver supporti PreparedStatements) poiché il driver non deve eseguire l'analisi SQL e la compilazione ciascuno volta che i parametri cambiano.
I guess che sarà una stringa. Ma i parametri di input verranno inviati al database e le conversioni / cast appropriate verranno applicate prima di creare un'istruzione SQL effettiva.
Per darti un esempio, potrebbe provare a vedere se CAST / Conversion funziona.
Se funziona, potrebbe creare una dichiarazione finale.
SELECT * From MyTable WHERE param = CAST('10; DROP TABLE Other' AS varchar(30))
Prova un esempio con un'istruzione SQL che accetta un parametro numerico.
Ora prova a passare una variabile stringa (con contenuto numerico accettabile come parametro numerico). Genera qualche errore?
Ora prova a passare una variabile stringa (con contenuto non accettabile come parametro numerico). Guarda cosa succede?
L'istruzione preparata è più sicura. Convertirà un parametro nel tipo specificato.
Ad esempio stmt.setString(1, user);
convertirà il user
parametro in una stringa.
Supponiamo che il parametro contenga una stringa SQL contenente un comando eseguibile : l'utilizzo di un'istruzione preparata non lo consentirà.
Aggiunge metacarattere (ovvero conversione automatica) a questo.
Questo lo rende più sicuro.
SQL injection: quando l'utente ha la possibilità di inserire qualcosa che potrebbe essere parte dell'istruzione sql
Per esempio:
Query stringa = "INSERT INTO students VALUES ('" + user + "')"
quando l'utente immette "Robert"); Studenti DROP TABLE; - "come input, provoca l'iniezione SQL
In che modo una dichiarazione preparata lo impedisce?
Query stringa = "INSERT INTO students VALUES ('" + ": name" + "')"
parameters.addValue ("nome", utente);
=> quando l'utente inserisce di nuovo "Robert"); Studenti DROP TABLE; - ", la stringa di input è precompilata sul driver come valori letterali e immagino che possa essere lanciata come:
CAST ( 'Robert'); Studenti DROP TABLE; - "AS varchar (30))
Quindi alla fine, la stringa verrà letteralmente inserita come nome della tabella.
http://blog.linguiming.com/index.php/2018/01/10/why-prepared-statement-avoids-sql-injection/
CAST(‘Robert’);
da CAST(‘Robert’); DROP TABLE students; –‘ AS varchar(30))
si spezzerebbe, quindi procederebbe con l'eliminazione della tabella se così fosse. Ferma l'iniezione, quindi credo che l'esempio non sia abbastanza completo per spiegare lo scenario.
Discorso preparato:
1) La precompilazione e la memorizzazione nella cache lato DB dell'istruzione SQL porta a un'esecuzione più rapida e alla capacità di riutilizzare la stessa istruzione SQL in batch.
2) Prevenzione automatica degli attacchi di SQL injection mediante l'escape incorporata di virgolette e altri caratteri speciali. Notare che ciò richiede l'utilizzo di uno qualsiasi dei metodi setXxx () PreparedStatement per impostare il valore.
Come spiegato in questo post , il PreparedStatement
solo non ti aiuta se stai ancora concatenando stringhe.
Ad esempio, un malintenzionato può ancora fare quanto segue:
Non solo SQL, ma anche JPQL o HQL possono essere compromessi se non si utilizzano parametri di bind.
In conclusione, non dovresti mai usare la concatenazione di stringhe durante la creazione di istruzioni SQL. Usa un'API dedicata a tale scopo:
Nelle istruzioni preparate l'utente è obbligato a inserire i dati come parametri. Se l'utente inserisce alcune istruzioni vulnerabili come DROP TABLE o SELECT * FROM USERS, i dati non saranno interessati poiché verrebbero considerati come parametri dell'istruzione SQL