In realtà ci sono due domande in una. E la domanda dal titolo ha ben poco a che fare con le preoccupazioni espresse dall'OP nei commenti successivi.
Anche se mi rendo conto che per l'OP è il loro caso particolare che conta, per i lettori provenienti da Google, è importante rispondere alla domanda più generale, che può essere formulata come "è la concatenazione sicura quanto le dichiarazioni preparate se mi sono assicurato che ogni letterale che sto concatenando è sicuro? ". Quindi, vorrei concentrarmi su quest'ultimo. E la risposta è
Assolutamente no.
La spiegazione non è così diretta come vorrebbe la maggior parte dei lettori, ma farò del mio meglio.
Stavo riflettendo sulla questione per un po ', risultando nell'articolo (sebbene basato sull'ambiente PHP) in cui ho cercato di riassumere tutto. Mi è venuto in mente che la questione della protezione dall'iniezione SQL spesso sfugge ad alcuni argomenti correlati ma più ristretti, come l'escape di stringhe, il casting dei tipi e simili. Sebbene alcune delle misure possano essere considerate sicure se prese da sole, non esiste un sistema né una semplice regola da seguire. Il che lo rende un terreno molto scivoloso, mettendo troppo sull'attenzione e l'esperienza dello sviluppatore.
La questione dell'SQL injection non può essere semplificata a una questione di particolare problema di sintassi. È più ampio della media degli sviluppatori abituati a pensare. È anche una questione metodologica . Non è solo "Quale particolare formattazione dobbiamo applicare", ma anche " Come deve essere fatto".
(Da questo punto di vista, un articolo di Jon Skeet citato nell'altra risposta sta andando piuttosto male che bene, poiché è di nuovo pignolo su alcuni casi limite, concentrandosi su un particolare problema di sintassi e non riuscendo ad affrontare il problema per intero.)
Quando stai cercando di affrontare la questione della protezione non nel suo insieme ma come un insieme di diversi problemi di sintassi, stai affrontando una moltitudine di problemi.
- l'elenco delle possibili scelte di formattazione è davvero enorme. Significa che si possono facilmente trascurare alcuni. Oppure confonderli (usando ad esempio l' escape di stringhe per l' identificatore ).
- Concatenazione significa che tutte le misure di protezione devono essere eseguite dal programmatore, non dal programma. Questo problema da solo porta a diverse conseguenze:
- tale formattazione è manuale. Manuale significa estremamente soggetto a errori. Si potrebbe semplicemente dimenticare di applicare.
- inoltre, c'è la tentazione di spostare le procedure di formattazione in qualche funzione centralizzata, confondendo ancora di più le cose e rovinando i dati che non andranno al database.
- quando sono coinvolti più sviluppatori, i problemi si moltiplicano per un fattore dieci.
- quando si usa la concatenazione, non si può dire a colpo d'occhio una query potenzialmente pericolosa: sono tutte potenzialmente pericolose!
A differenza di quel pasticcio, le dichiarazioni preparate sono davvero il Santo Graal:
- può essere espresso sotto forma di una semplice regola facile da seguire.
- è essenzialmente una misura non rilevabile, significa che lo sviluppatore non può interferire e, volontariamente o meno, rovinare il processo.
- la protezione dall'iniezione è in realtà solo un effetto collaterale delle dichiarazioni preparate, il cui vero scopo è produrre affermazioni sintatticamente corrette. E un'affermazione sintatticamente corretta è a prova di iniezione al 100%. Tuttavia, abbiamo bisogno che la nostra sintassi sia corretta nonostante qualsiasi possibilità di iniezione.
- se utilizzato tutto intorno, protegge l'applicazione indipendentemente dall'esperienza dello sviluppatore. Diciamo, c'è una cosa chiamata iniezione di secondo ordine . E un'illusione molto forte che dice "per proteggere, sfuggire a tutti gli input forniti dall'utente ". Combinati insieme, portano all'iniezione, se uno sviluppatore si prende la libertà di decidere, cosa deve essere protetto e cosa no.
(Pensando ulteriormente, ho scoperto che l'attuale set di segnaposto non è sufficiente per le esigenze della vita reale e deve essere esteso, sia per le strutture di dati complesse, come gli array, sia per le parole chiave o gli identificatori SQL, che a volte devono essere aggiunti al interrogare dinamicamente anche, ma uno sviluppatore è lasciato disarmato per un caso del genere e costretto a ripiegare sulla concatenazione di stringhe, ma questa è un'altra questione).
È interessante notare che la controversia di questa domanda è provocata dalla natura molto controversa di Stack Overflow. L'idea del sito è quella di avvalersi di particolari domande degli utenti che chiedono direttamente per raggiungere l'obiettivo di avere un database di risposte generiche adatte agli utenti che provengono dalla ricerca . L'idea di per sé non è male , ma fallisce in una situazione come questa: quando un utente pone una domanda molto ristretta , in particolare per ottenere un argomento in una disputa con un collega (o per decidere se vale la pena refactoring del codice). Mentre la maggior parte dei partecipanti esperti sta cercando di scrivere una risposta, tenendo presente la missione di Stack Overflow nel suo complesso, rendendo la loro risposta valida per il maggior numero possibile di lettori, non solo per l'OP.