¿Es posible la inyección SQL incluso en una statement preparada?

Leí muchos artículos sobre Desbordamiento de stack con respecto a cómo se puede prevenir la inyección de SQL usando declaraciones preparadas

Pero, ¿hay alguna forma de inyectar SQL incluso en declaraciones preparadas o es 100% seguro?

A continuación se muestra mi código java

String query = "SELECT * FROM Users WHERE username=? and password=?"; ps=con.prepareStatement(query); ps.setString(1,username); ps.setString(2,password); rs = ps.executeQuery(); status = rs.next(); if(status==true){ ..... }else{ .... } 

Probé algunas consultas de inyección de SQL como

Algunas entradas:

 SELECT * FROM users WHERE username = 'xxx@xxx.xxx' OR 1 = 1 LIMIT 1 -- ' ] AND password = md5('1234'); SELECT * FROM users WHERE email = 'xxx@xxx.xxx' AND password = md5('xxx') OR 1 = 1 -- ]'); 

También he intentado con algunas consultas más, pero como la (comilla simple) se escapa (/ ‘), ninguna de las consultas de inyección de SQL parece funcionar.

Por favor, sugiérame si hay alguna consulta / técnica de inyección de SQL que pueda aplicarse para hacer la inyección de SQL en el código anterior.

Esta consulta: String query = "SELECT * FROM Users WHERE username=? and password=?"; es seguro, ya que cualesquiera que sean los parámetros, aún se ejecutará como una simple selección. A lo sumo, terminará navegando por una tabla entera.

Pero una statement preparada es solo una herramienta y los progtwigdores (malos) todavía pueden usarla de forma incorrecta.

Veamos la siguiente consulta.

 String query = "SELECT id, " + paramName + " FROM Users WHERE username=? and password=?"; 

donde paramName sería un nombre de parámetro. Es tan seguro como paramName es paramName , porque usa directamente una variable para construir la cadena que será analizada por el motor de base de datos. Aquí PreparedStatement no puede ayudar porque JDBC no permite parametrizar un nombre de columna.

Así que la regla aquí será:

  • ¡Evita tal construcción si puedes!
  • si realmente lo necesita, compruebe (regexes, lista de cadenas permitidas, etc.) que paramName no puede ser otra cosa que lo que espera porque ese control es la única prevención contra la inyección de SQL