7

Il codice di seguito è SAMATE Reference Dataset. L'ho usato per testare uno strumento di analisi statica. Come si può vedere il codice dovrebbe prevenire l'SQL-Injection sia usando un metodo di sanitizzazione sia usando un'istruzione preparata.L'istruzione preparata impedisce SQL-Injection qui

Poiché gli strumenti SCA non sono in grado di conoscere i metodi di santitizzazione personalizzati, non viene rilevato che il metodo allowed viene utilizzato per impedire l'iniezione.

public class SQLInjection_good_089 extends HttpServlet 
{ 
    private static final long serialVersionUID = 1L; 

    public SQLInjection_good_089() 
    { 
     super(); 
    } 

    // Table of allowed names to use 
    final String allowed_names[] = { "Mickael", "Mary", 
      "Peter", "Laura", "John"}; 

    // Function to check if the current name takes part of the allowed ones 
    public boolean allowed(String in) 
    { 
     boolean bool = false; 

     for(int i = 0; i < 5; i++) 
     { 
      if(in.equals(allowed_names[i])) 
      { 
       // the current name is allowed to use 
       bool = true; 
       break; 
      } 
     } 
     return bool; 
    } 

    // Method which will be called to handle HTTP GET requests 
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
     throws ServletException, IOException 
    { 
     // Initialize the output stream 
     resp.setContentType("text/html"); 
     ServletOutputStream out = resp.getOutputStream(); 
     out.println("<HTML><BODY><blockquote><pre>"); 
     Connection conn = null; 

     // Get the parameter "name" from the data provided by the user 
     String name = req.getParameter("name"); 

     if ((name != null) && (allowed(name) == true)) 
     { 
      try 
      { 
       // Set the context factory to use to create the initial context 
       System.setProperty (Context.INITIAL_CONTEXT_FACTORY, "your.ContextFactory"); 

       // Create the initial context and use it to lookup the data source 
       InitialContext ic = new InitialContext(); 
       DataSource dataSrc = (DataSource) ic.lookup ("java:comp/env/jdbc:/mydb"); 

       // Create a connection to the SQL database from the data source 
       conn = dataSrc.getConnection(); 

       // Send a SQL request to the database 
       PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE firstname LIKE ?"); 
       // replace the first parameter by name 
       ps.setString(1, name); 
       ps.executeQuery(); 
      } 
      catch(NamingException e) 
      { 
       out.println("Naming exception"); 
      } 
      catch(SQLException e) 
      { 
       out.println("SQL exception"); 
      } 
      finally 
      { 
       try 
       { 
        if (conn != null) 
         conn.close(); 
       } 
       catch (SQLException se) 
       { 
        out.println("SQL Exception"); 
       } 
      } 
     } 
     else 
      return; 

     out.println("</pre></blockquote></body></html>"); 
    } 

    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
     throws ServletException, IOException 
    { 
    } 
} 

Tuttavia, penso che l'uso di una dichiarazione preparata dovrebbe comunque impedire l'iniezione qui. Mi sbaglio?

risposta

3

Sei corretto. Lo prepared statement si prenderà cura dell'input SQL "illegale".

La funzione allowed(...) è una specie di validazione dell'input dell'utente in termini di regole di business e non per prevenire SQL injection.

+0

Questo era un problema tecnico di me stesso. Ho accidentalmente cercato i risultati per il progetto sbagliato. Non importa. Grazie – er4z0r

1

Proprio la dichiarazione preparata dovrebbe essere sufficiente per prevenire SQL injection ...

Tuttavia, se avete intenzione di scrivere messaggi degli utenti per il parametro 'out' (come out.printf("Invalid username %s", name)), attenzione per javascript iniezione. Potrei inserire il mio nome come <script>alert('hi')</script>

1

Sembra impedire l'iniezione SQL. Ovviamente sei corretto che la funzione consentita() sia d'aiuto, ma non è esattamente il metodo preferito. Dato che il tuo codice è solo un esempio, suppongo che nel mondo reale la maggior parte dei programmi consenta più di 5 possibili opzioni.

3

Sì L'istruzione preparata impedisce l'iniezione sql. Questo perché stai usando il segnaposto (?) Nella query. È il segnaposto che è importante notare qui.

Di seguito sono riportati 2 esempi di dichiarazioni preparate. Il primo non impedirà l'iniezione sql.

PreparedStatement ps = conn.prepareStatement ("SELECT * FROM users WHERE firstname LIKE" + name);

La dichiarazione di cui sopra, anche se è preparato dichiarazione non impedirà SQL injection

Tuttavia la dichiarazione seguente preparata è buono per prevenire SQL injection.

PreparedStatement ps = conn.prepareStatement ("SELECT * FROM users WHERE firstname LIKE?");

La differenza tra la prima e la seconda istruzione è che mentre la query nel primo caso viene compilata dinamicamente in fase di esecuzione, ma nel secondo caso è precompilata.

Ciò significa che l'input dell'utente malintenzionato come (a'or'1 '=' 1) può modificare la query nella prima istruzione. Ma la seconda query poiché è precompilata tratterà l'input dell'utente malintenzionato come comando di dati e non di sql.

In breve Le istruzioni di Preapred impediscono l'SQL Injection se e solo se vengono utilizzate con segnaposti e parametri di binding.