7

El código siguiente es de SAMATE Reference Dataset. Lo usé para probar una herramienta de análisis estático. Como puede ver, el código debe evitar la inyección de SQL tanto al usar un método de desinfección como al usar una declaración preparada.¿Prepara la instrucción prevenir SQL-Injection aquí

Como las herramientas de SCA no pueden conocer los métodos de santitzación personalizados, no detectarán que el método allowed se usa para evitar la inyección.

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

Sin embargo, creo que el uso de una declaración preparada debe evitar la inyección aquí de todos modos. ¿Estoy equivocado?

Respuesta

3

Estás en la correcta. El prepared statement se ocupará de la entrada 'ilegal' de SQL.

La función allowed(...) es una especie de validación de entrada de usuario en términos de reglas de negocio y no para evitar la inyección SQL.

+0

Acutally esto fue un error de mí mismo. Accidentalmente miré los resultados para el proyecto equivocado. No importa. Gracias – er4z0r

1

Sólo la declaración preparada debe ser suficiente para evitar la inyección de SQL ...

Sin embargo, si usted tiene la intención de escribir mensajes de usuario para el parámetro 'out' (como out.printf("Invalid username %s", name)), cuidado con javascript inyección. Pude ingresar mi nombre como <script>alert('hi')</script>

1

Parece que previene la inyección de SQL. Por supuesto, es correcto que la función permitida() ayuda, pero no es exactamente el método preferido. Dado que su código es solo una muestra, asumiría que en el mundo real la mayoría de los programas permitirían más de 5 opciones posibles.

3

Sí La declaración preparada aquí evitará la inyección sql. Esto se debe a que está utilizando el marcador de posición (?) En la consulta. Es el marcador de posición que es importante tener en cuenta aquí.

A continuación se muestran 2 ejemplos de declaraciones preparadas. El primero no evitará la inyección sql.

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

La declaración anterior, incluso si se prepara declaración no impedirá la inyección sql

Sin embargo, la siguiente declaración preparada es bueno para evitar la inyección de SQL.

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

La diferencia b/w de la primera y segunda afirmación es que mientras la consulta en el primer caso se compila dinámicamente en tiempo de ejecución, pero en el segundo caso se precompila.

Esto significa que la entrada de usuarios maliciosos como (a'or'1 '=' 1) puede alterar la consulta en la primera instrucción. Pero la segunda consulta, ya que está precompilada, tratará la entrada de usuarios maliciosos como datos y no como comandos sql.

En pocas palabras Las instrucciones prevenidas previenen la inyección de SQL si y solo si se usan con marcadores de posición y parámetros de vinculación.