venerdì 3 febbraio 2012

Java Sql dinamico immune da SQL Injection

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;
    }

Nessun commento:

Posta un commento