Uno dei problemi frequenti con l'Sql dinamico è il rischio di SQL Injection.
Infatti spesso si tende a costruire le query dinamiche semplicemente concatenando le stringhe con i parametri.
Vediamo come realizzare l'SQL dinamico utilizzando una web app.
L'esempio è realizzato usando semplicemente JDBC, ma si può in maniera analoga estendere a JPA.
Il concetto base è che per evitare SQL Injection bisogna utilizzare i PreparedStatement, quindi in generale non concatenando stringhe ma utilizzando i placeholder (in JDBC e in JPA si usa il ?), rendendo quindi la query dinamica e non statica come con la semplice concatenazione dei parametri.
Vediamo un esempio molto semplice, abbiamo un form con 3 campi di ricerca, Nome Cognome ed Età e vogliamo costruire la nostra query dinamica.
La stringa della Query in questo semplice caso è una costante presente in una classe, ed è così definita:
public static String GET_ANAGRAFICA="select * from persona where 1=1 /*1 " +
"and nome like ? 1*/ /*2 and cognome like ?2*/ " +
" /*3 and eta=? 3*/";
Come possiamo notare i parametri sono commentati (/*1....1*/).
Lato Web sono impostati i parametri nelle form e quindi si effettua l'invio ad una Servlet che si occupa di evadere la richiesta (non posto il codice che è banale).
Quello che avviene a questo punto nel metodo che si occupa nel Back End di ritornare i dati all'utente è il seguente:
public List<Persona> getListaCompletaPersone(Persona p){
List<Persona> lista=new ArrayList<Persona>();
try
{
PreparedStatement pst=getDs().getConnection().prepareStatement(lavoraQuery(p));
pst.setString(1, "%"+p.getNome()+"%");
pst.setString(2,"%"+ p.getCognome()+"%");
pst.setInt(3, p.getEta());
ResultSet rs=pst.executeQuery();
while(rs.next()){
Persona pp=new Persona();
pp.setCognome(rs.getString("cognome"));
pp.setEta(rs.getInt("eta"));
pp.setNome(rs.getString("nome"));
lista.add(pp);
}
pst.close();
rs.close();
}
catch(Exception ex){
ex.printStackTrace();
}
return lista;
}
Il metodo chiave per la creazione della stringa è il lavoraQuery che nel caso in cui sia presente uno o più dei parametri toglie i commenti relativi, rendendo quindi la selezione effettiva.
private String lavoraQuery(Persona p){
String qry=Query.GET_ANAGRAFICA;
if(p.getCognome()!=null && !p.getCognome().trim().equals("")){
qry=qry.replace("/*2", "");
qry=qry.replace("2*/", "");
}
if(p.getNome()!=null && !p.getNome().trim().equals("")){
qry=qry.replace("/*1", "");
qry=qry.replace("1*/", "");
}
if(p.getEta()!=0){
qry=qry.replace("/*3", "");
qry=qry.replace("3*/", "");
}
return qry;
}
Infatti spesso si tende a costruire le query dinamiche semplicemente concatenando le stringhe con i parametri.
Vediamo come realizzare l'SQL dinamico utilizzando una web app.
L'esempio è realizzato usando semplicemente JDBC, ma si può in maniera analoga estendere a JPA.
Il concetto base è che per evitare SQL Injection bisogna utilizzare i PreparedStatement, quindi in generale non concatenando stringhe ma utilizzando i placeholder (in JDBC e in JPA si usa il ?), rendendo quindi la query dinamica e non statica come con la semplice concatenazione dei parametri.
Vediamo un esempio molto semplice, abbiamo un form con 3 campi di ricerca, Nome Cognome ed Età e vogliamo costruire la nostra query dinamica.
La stringa della Query in questo semplice caso è una costante presente in una classe, ed è così definita:
public static String GET_ANAGRAFICA="select * from persona where 1=1 /*1 " +
"and nome like ? 1*/ /*2 and cognome like ?2*/ " +
" /*3 and eta=? 3*/";
Come possiamo notare i parametri sono commentati (/*1....1*/).
Lato Web sono impostati i parametri nelle form e quindi si effettua l'invio ad una Servlet che si occupa di evadere la richiesta (non posto il codice che è banale).
Quello che avviene a questo punto nel metodo che si occupa nel Back End di ritornare i dati all'utente è il seguente:
public List<Persona> getListaCompletaPersone(Persona p){
List<Persona> lista=new ArrayList<Persona>();
try
{
PreparedStatement pst=getDs().getConnection().prepareStatement(lavoraQuery(p));
pst.setString(1, "%"+p.getNome()+"%");
pst.setString(2,"%"+ p.getCognome()+"%");
pst.setInt(3, p.getEta());
ResultSet rs=pst.executeQuery();
while(rs.next()){
Persona pp=new Persona();
pp.setCognome(rs.getString("cognome"));
pp.setEta(rs.getInt("eta"));
pp.setNome(rs.getString("nome"));
lista.add(pp);
}
pst.close();
rs.close();
}
catch(Exception ex){
ex.printStackTrace();
}
return lista;
}
Il metodo chiave per la creazione della stringa è il lavoraQuery che nel caso in cui sia presente uno o più dei parametri toglie i commenti relativi, rendendo quindi la selezione effettiva.
private String lavoraQuery(Persona p){
String qry=Query.GET_ANAGRAFICA;
if(p.getCognome()!=null && !p.getCognome().trim().equals("")){
qry=qry.replace("/*2", "");
qry=qry.replace("2*/", "");
}
if(p.getNome()!=null && !p.getNome().trim().equals("")){
qry=qry.replace("/*1", "");
qry=qry.replace("1*/", "");
}
if(p.getEta()!=0){
qry=qry.replace("/*3", "");
qry=qry.replace("3*/", "");
}
return qry;
}
Nessun commento:
Posta un commento