sql >> Base de Datos >  >> RDS >> Oracle

Delphi:prevención contra la inyección de SQL

Seguro

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

Este código es seguro porque está utilizando parámetros.
Los parámetros siempre están a salvo 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 nombre de usuario podría ser name; Drop table_name; Resultando en la ejecución de 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; -- Dará como resultado 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);

Porque IntToStr() solo aceptará números enteros, por lo que no se puede inyectar código SQL en la cadena de consulta de esta manera, solo números (que es exactamente lo que desea y, por lo tanto, está permitido)

Pero quiero hacer cosas que no se pueden hacer con parámetros

Los parámetros solo se pueden utilizar para valores. No pueden reemplazar nombres de campos o nombres de tablas. Entonces, si desea 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 parámetros para los nombres de tablas o campos.
La segunda consulta no es segura, pero es la única manera de hacerlo.
¿Cómo mantenerse a salvo?

Tienes que comprobar la cadena tablename contra una lista 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 manera de hacer esto, que yo sepa.

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

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

Debería ser

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

No puedes tener dos where 's en una (sub)consulta