Delphi: evita la inyección de SQL

Necesito proteger una aplicación de inyección SQL. La aplicación se conecta a Oracle, utilizando ADO, y busca el nombre de usuario y la contraseña para realizar la authentication.

Por lo que he leído hasta ahora, el mejor enfoque es usar parameters, no asignar todo el SQL como cadena. Algo como esto:

query.SQL.Text := 'select * from table_name where name=:Name and id=:ID'; query.Prepare; query.ParamByName( 'Name' ).AsString := name; query.ParamByName( 'ID' ).AsInteger := id; query.Open; 

Además, estoy pensando en verificar la input del usuario y eliminar palabras key de SQL como eliminar, insert, seleccionar, etc. Se eliminará cualquier carácter de input diferente a las letras y numbers ASCII normales.

Esto me asegurará un mínimo de nivel de security?

No quiero usar ningún otro componente que el estándar Delphi 7 y el Jedi.

Seguro

 query.SQL.Text := 'select * from table_name where name=:Name'; 

Este código es seguro porque estás usando parameters.
Los parameters están siempre seguros de la inyección de SQL.

Inseguro

 var Username: string; ... query.SQL.Text := 'select * from table_name where name='+ UserName; 

No es seguro porque el name; Drop table_name; usuario podría ser el name; Drop table_name; name; Drop table_name; Como resultado, se ejecuta la siguiente consulta.

 select * from table_name where name=name; Drop table_name; 

También inseguro

 var Username: string; ... query.SQL.Text := 'select * from table_name where name='''+ UserName+''''; 

Porque si el nombre de usuario es ' or (1=1); Drop Table_name; -- ' or (1=1); Drop Table_name; -- ' or (1=1); Drop Table_name; -- Se generará la siguiente consulta:

 select * from table_name where name='' or (1=1); Drop Table_name; -- ' 

Pero este código es seguro

 var id: integer; ... query.SQL.Text := 'select * from table_name where id='+IntToStr(id); 

Debido a que IntToStr() solo aceptará integers, por lo que no se puede IntToStr() código SQL en la cadena de consulta de esta manera, solo numbers (que es exactamente lo que quiere y, por lo tanto, permite)

Pero quiero hacer cosas que no se pueden hacer con parameters

Los parameters solo se pueden usar para valores. No pueden replace nombres de campos o tablas. Entonces, si quieres ejecutar esta consulta

 query:= 'SELECT * FROM :dynamic_table '; {doesn't work} query:= 'SELECT * FROM '+tableName; {works, but is unsafe} 

La primera consulta falla porque no puede usar parameters para nombres de tablas o campos.
La segunda consulta no es segura, pero es la única manera en que esto se puede hacer.
¿Cómo te mantienes seguro?

tablename verificar el nombre de tablename cadena con una list de nombres aprobados.

 Const ApprovedTables: array[0..1] of string = ('table1','table2'); procedure DoQuery(tablename: string); var i: integer; Approved: boolean; query: string; begin Approved:= false; for i:= lo(ApprovedTables) to hi(ApprovedTables) do begin Approved:= Approved or (lowercase(tablename) = ApprovedTables[i]); end; {for i} if not Approved then exit; query:= 'SELECT * FROM '+tablename; ... 

Esa es la única forma de hacer esto, que yo sepa.

Por cierto, su código original tiene un error:

 query.SQL.Text := 'select * from table_name where name=:Name where id=:ID'; 

Debiera ser

 query.SQL.Text := 'select * from table_name where name=:Name and id=:ID'; 

No puede tener dos where una (sub) consulta

Si permite que el usuario influya solo en el valor de los parameters que se vincularán en un text de command sql con marcadores de position, entonces realmente no necesita inspeccionar lo que el usuario ingresa: la forma más simple de evitar la inyección SQL, como usted menciona, es evitar SQL concatenado, y usar variables enlazadas (o procedimientos de llamada) lo hace (también tiene la ventaja – el kilometraje / relevancia depende de la database – de permitir que el motor reutilice los planes de consulta).

Si está utilizando Oracle, entonces debe tener una buena razón para no usar variables vinculadas: Tom Kyte tiene mucha información sobre esto en su sitio http://asktom.oracle.com . Simplemente ingrese "variables enlazadas" en el cuadro de búsqueda.

Esto me asegurará un mínimo de nivel de security?

Sí, las consultas parametrizadas deberían protegerlo de la inyección SQL, que sería fácil de probar. Simplemente ingrese una cadena peligrosa en la variable de name y vea qué sucede. Normalmente deberías get 0 filas devueltas y no un error.