Query parametriche con Access 2003

lunedì 25 febbraio 2008 - 17.10

paquito_ita Profilo | Senior Member

Ciao,

vorrei usare delle query parametriche per tutelare il sito web da attacchi di tipo SQL injection. In particolare nel caso dove l'utente puo' riempire i campi di una form per esegure la ricerca di un documento all'interno del sito in base a diversi criteri: ID, titolo, autore, ecc.

Userei il codice seguente :

Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra

Nel'esempio ho considerato come parametro solo l'ID, ma ovviamente dovrei usare un parametro per ogni campo della form. Il problema è che non so a priori quali campi verranno riempiti dall'utente ed il metodo dovrebbe essere valido in tutti i casi.

Come potrei ottenere un comportamento del tipo:
se il campo non è vuoto (e non è uno spazio bianco) usalo come parametro nella query, altrimenti non inserire tale condizione/parametro nel WHERE.

Grazie in anticipo per ogni consiglio!!!

alx_81 Profilo | Guru

>Ciao,
Ciao!
>
>Il problema è che non so a priori quali campi verranno riempiti dall'utente
>ed il metodo dovrebbe essere valido in tutti i casi.
>Come potrei ottenere un comportamento del tipo:
>se il campo non è vuoto (e non è uno spazio bianco) usalo come
>parametro nella query, altrimenti non inserire tale condizione/parametro
>nel WHERE.
Solito annoso problema delle query dinamiche.
Perdendo prestazioni potresti usare nella where condition condizioni del tipo

WHERE campo = @Parametro OR @Parametro IS NULL

In questo modo riempiresti facilmente la collezione dei parametri.
Se cerchi le query costruite dinamicamente, non puoi sapere a priori il numero dei parametri quindi da codice non puoi aggiungerli correttamente
Puoi pensare di comporre dinamicamente l'intera where lato codice per poi eseguire il comando.
Puoi anche pensare, se hai un DBMS che supporta del stored procedure, di passare i parametri in modo da comporre la where proprio nella procedura ed eseguirla al volo.

Ognuna di queste soluzioni, non è delle migliori, si cerca sempre di evitare SQL dinamico. Quello che ti chiedo è:
- Non puoi limitare i filtri?
- Non puoi gestire i casi con dei semplici if per le combinazioni dei parametri da passare?

Se devi farlo per tutta la form, io non vedo altre soluzioni al di fuori del SQL dinamico o della where su tutti i campi come nominato all'inizio.

>
>Grazie in anticipo per ogni consiglio!!!
Di nulla!

Alx81 =)

http://blogs.dotnethell.it/suxstellino
http://mvp.support.microsoft.com/profile/Alessandro.Alpi
http://italy.mvps.org

paquito_ita Profilo | Senior Member

Ciao Alx,

>Quello che ti chiedo è:
>- Non puoi limitare i filtri?
>- Non puoi gestire i casi con dei semplici if per le combinazioni dei parametri da passare?
>Se devi farlo per tutta la form, io non vedo altre soluzioni al di fuori del SQL dinamico o della where su tutti i campi come
>nominato all'inizio.

Ho una sola form di ricerca, quindi il caso si presenta solo per questa. Non posso usare stored procedure per ragioni "logistiche", ovvero il mio sito è "sperimentale" ed il capo non gradicse molto che metta mano al DB...

AL momento uso degli IF che controllano che i vari campi non siano vuoti e che rispettino delle espressioni regolari (ad es. L'ID composto di soli numeri), se tali controlli vengono soddisfatti creo il parametro relativo.

Il problema è che la gestione/esecuzione delle query la faccio in una classe apposita (in modo da suddividere chiaramente le diverse responsabilità).
Peroò, ora che ci penso, potrei fare un Vector di parametri e lo passo alla classe che gestisce le query, dove c'è l'istanza di OdbcCommand alla quale aggiungo i vari parametri.

Che ne pensi? A livello di sicurezza/prestazioni come si presenta tale soluzione?
Di nuovo grazie mille per la disponibilità

alx_81 Profilo | Guru

>Che ne pensi? A livello di sicurezza/prestazioni come si presenta tale soluzione?
essendo dinamica e a codice non sarà il massimo come prestazioni. Se non puoi mettere mano al db, puoi creare dinamicamente la where e basta. Non hai tante soluzioni..

>Di nuovo grazie mille per la disponibilità
figurati

Alx81 =)

http://blogs.dotnethell.it/suxstellino
http://mvp.support.microsoft.com/profile/Alessandro.Alpi
http://italy.mvps.org

paquito_ita Profilo | Senior Member

Alla fine ho fatto come mi hai consigliato tu, creando i parametri se sono soddisfatti gli if.

Tuttavia la query non la eseguo nella stessa classe in cui creo i parametri (classe FilterDoc.aspx, dove ho le textField della form di ricerca), ma la invio alla classe DocRepository.aspx (che deve visualizzare i risultati della ricerca) affinchè da lì vengano invocati i metodi (statici) per eseguire la query che risulta:
Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra


E' corretto usare cosi' i parametri?

I valori dei parametri li aggiungo all'istanza OdbcCommand che viene creata all'interno del metodo statico incaricato di eseguire la query.

Se non riempio i field della form relativi ai parametri, la query ha successo e viene visualizzata la prima (di sei, per esempio) pagine di una GridView. Se tuttavia seleziono un'altra pagina della GridView (e quindi la query viene rieseguita per la natura della GridView) non ottengo nessun risultato.

Questo è dovuto al fatto che passo dalla classe FilterDoc.aspx alla classe DocRepository.aspx attraverso il metodo:
Server.Transfer("~/docsRepository.aspx?MyDesk=false&projID=" + projID + "&filter=yes"); HttpContext.Current.Items["filterQuery"] = query; HttpContext.Current.Items["filterParams"] = parameters;

Dove HttpContext.Current.Items mi servono per portarmi dietro il corpo della query e i parametri che andranno aggiunti all'istnza di OdbcCommand. Tuttavia eseguendo il debug ho visto che quando seleziono un'altra pagina della GridView, quando eseguo Context.Items non ci sono piu' le chiavi "filterQuery" e "filterParams", ce invece c'erano prima.

Come potrei risolvere cio'? Riconosco che forse non è proprio chiarissima la spiegazione, se servono ulteriori delucidazioni chiedimi pure!

Grazie mille

alx_81 Profilo | Guru

>E' corretto usare cosi' i parametri?
no, trasforma le like in LIKE '%' + @parametro + '%'

E se possibile, utilizza il % solo alla fine, così almeno la ricerca è più performante (cerca di indicizzare i campi su cui fai le where).
>
>Se non riempio i field della form relativi ai parametri, la query
>ha successo e viene visualizzata la prima (di sei, per esempio)
>pagine di una GridView. Se tuttavia seleziono un'altra pagina
>della GridView (e quindi la query viene rieseguita per la natura
>della GridView) non ottengo nessun risultato.
Come gestisci l'evento del cambio pagina? Hai rifatto il databind della grid dopo aver cambiato pagina?
Io non userei la server transfer, bensì un semplice redirect passando alcuni parametri in get e magari salvando in sessione l'elenco dei parametri.
Per questo, però ti consiglio di aprire un nuovo thread, poichè non siamo nella stanza corretta.


Alx81 =)

http://blogs.dotnethell.it/suxstellino
http://mvp.support.microsoft.com/profile/Alessandro.Alpi
http://italy.mvps.org

paquito_ita Profilo | Senior Member

Ciao Alx81,

>>E' corretto usare cosi' i parametri?
>no, trasforma le like in LIKE '%' + @parametro + '%'

Non ho ben capito, perdonami
Io da codice creo così i miei parametri (seguendo la tua indicazione):
parametricalQuery += "AND Documents.Autor LIKE '%' + @title + '%' ";
Ma poi così mi ritrovo la query:
Documents.Autor LIKE '%' + @author + '%'

Che non viene accettata.Se cambio in LIKE '%'@title'%', ho un errore ODBC che dice che c'è un operatore mancante. Se cambio in LIKE '%@title%' Ottengo come errore: Parametri insufficienti. Previsto 1 (anche se i parametri relativi ai LIKE non vengono creati).
I parametri li passo come ArrayList alla classe dove è presente l'istanza di OdbcCommand ed eseguo un ciclo per aggiungerli: foreach (OdbcParameter indx in parameters)
{
command.Parameters.Add(indx);
}

Ma non rieco a cavarci le gambe Da cosa puo' dipendere?

alx_81 Profilo | Guru

>Ma non rieco a cavarci le gambe Da cosa puo' dipendere?
dall'odbc.. non puoi usare oledb?

Alx81 =)

http://blogs.dotnethell.it/suxstellino
http://mvp.support.microsoft.com/profile/Alessandro.Alpi
http://italy.mvps.org

paquito_ita Profilo | Senior Member

Ciao Alx81,

>>Ma non rieco a cavarci le gambe Da cosa puo' dipendere?
>dall'odbc.. non puoi usare oledb?

Non saprei... Penso di sì, ma non ho alcuna esperienza a riguardo. DI seguito ti posto il codice che uso per eseguire la query. Il metodo accetta il corpo della querySQL e i parametri (che vengono aggiunti correttamente all'istanza OdbcCommand, l'ho verificato in debug). L'istanza DataSet restituita viene poi usata per il metodo bindList() per popolare la GridView.
Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra
Se anche vedendo il codice, rimani convinto che il problema sia dell'Odbc, mi potresti indicare come risolvere la faccenda con l'Oledb?
Sarei immensamente grato

alx_81 Profilo | Guru

>Ciao Alx81,
Ciao

>Se anche vedendo il codice, rimani convinto che il problema sia
>dell'Odbc, mi potresti indicare come risolvere la faccenda con
>l'Oledb?
diciamo che non credo che ODBC capisca i parametri definiti con @nomeparam. Comunque, io riscriverei il codice così:
Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra

provalo con la stringa sql che componi..
Alx81 =)

http://blogs.dotnethell.it/suxstellino
http://mvp.support.microsoft.com/profile/Alessandro.Alpi
http://italy.mvps.org

paquito_ita Profilo | Senior Member

Ciao Alx81,

purtroppo io suo come database Access 2003 (lazienda usa ancora quello, sigh), quindi non posso usare i metodi con "Sql" come prefisso, ma solo "Odbc".

Spero si riesca a trovare una soluzione, anche se al momento non mi viee in mente nulla

Grazie comunque!!!

alx_81 Profilo | Guru

>purtroppo io suo come database Access 2003 (lazienda usa ancora
>quello, sigh), quindi non posso usare i metodi con "Sql" come
>prefisso, ma solo "Odbc".
allora hai anche Jet, il provider OLEDB per access.
Eccoti il codice:

Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra

a questo codice va associata una connectionstring formattata come questa:

Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra

ciao!
Alx81 =)

http://blogs.dotnethell.it/suxstellino
http://mvp.support.microsoft.com/profile/Alessandro.Alpi
http://italy.mvps.org

paquito_ita Profilo | Senior Member

Ciao Alx,

Mitico , funziona!!! Semplicemente avendo cambiato Odbc con OleDb!!!

Tuttavia ora mi è sorto un piccolo problema (mi permetto di abusare della tua grande disponibilità ). Nella pagina (Docs.aspx) in cui invoco l'esecuzione della query (e dove poi visualizzo i risultati) ci sono anche due button: FilterData e Back.
Se l'utente clicca sul bottone Back, il metodo page_load della classe Docs.aspx viene invocato nuovamente e vengono eseguite di nuovo le query, per poi arrivare ad eseguire l'evento on_click relativo al button e che semplicemente fa tornare indietro alla pagina precedente.

Ho provato ad usare anche una condizione con Page.isPostBack, ma non va bene, perché mi risulta false.

Se non ho usato la pagina di search (con le relative query parametriche), funziona senza errori, anche se non è molto efficiente in quanto vengono ripetute, inutilmente, le query.
Se invece la pagina è visualizzata con i risultati della ricerca, alla pressione di uno dei due button ho un errore, perché la stessa query parametrica viene di nuovo invocata.
L'errore è: "The OleDbParameter is already contained by another OleDbParameterCollection."

Come faccio quindi a evitare che tutte le query vengano invocate e saltare subito all'esecuzione del corpo dell'evento on_click? La cosa è complicata dal fatto che la stessa pagina viene acceduta da altri punti del sito e per ognuno dei quali deve eseguire una diversa query.

Ti ringrazio infinitamente per la tua pazienza!!!!!

alx_81 Profilo | Guru

>Ciao Alx,
Ciao

>Ho provato ad usare anche una condizione con Page.isPostBack,
>ma non va bene, perché mi risulta false.

Di solito nella load si usa una cosa del tipo
if (!Page.IsPostBack) { // binding dei dati }

oppure, hai anche la proprietà IsCrossPagePostBack:
if (!Page.IsCrossPagePostBack) { // binding dei dati }

le guide qui:

Page.IsCrossPagePostback
http://msdn2.microsoft.com/en-us/library/system.web.ui.page.iscrosspagepostback.aspx

Page.IsPostBack
http://msdn2.microsoft.com/en-us/library/system.web.ui.page.ispostback.aspx


in poche parole, la prima volta che carichi la pagina effettui i collegamenti ai dai e i vari calcoli/logiche..
dopo la prima salti sempre la parte all'interno dell'if..

>Ti ringrazio infinitamente per la tua pazienza!!!!!
di nulla!
Alx81 =)

http://blogs.dotnethell.it/suxstellino
http://mvp.support.microsoft.com/profile/Alessandro.Alpi
http://italy.mvps.org
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2023
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5