Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Delphi - previne contra injeção de SQL


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

Este código é seguro porque você está usando parâmetros.
Os parâmetros estão sempre protegidos contra injeção de SQL.

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

Não é seguro porque o nome de usuário pode ser name; Drop table_name; Resultando na execução da seguinte consulta.
select * from table_name where name=name; Drop table_name;

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

Porque se username for ' or (1=1); Drop Table_name; -- Isso resultará na seguinte consulta:
select * from table_name where name='' or (1=1); Drop Table_name; -- '

Mas este código é seguro
var id: integer;
...
query.SQL.Text := 'select * from table_name where id='+IntToStr(id);

Porque IntToStr() aceitará apenas números inteiros para que nenhum código SQL possa ser injetado na string de consulta dessa maneira, apenas números (que é exatamente o que você deseja e, portanto, permitido)

Mas eu quero fazer coisas que não podem ser feitas com parâmetros

Os parâmetros só podem ser usados ​​para valores. Eles não podem substituir nomes de campos ou nomes de tabelas. Portanto, se você deseja executar esta consulta
query:= 'SELECT * FROM :dynamic_table '; {doesn't work}
query:= 'SELECT * FROM '+tableName;      {works, but is unsafe}

A primeira consulta falha porque você não pode usar parâmetros para nomes de tabelas ou campos.
A segunda consulta não é segura, mas é a única maneira de fazer isso.
Como você se mantém seguro?

Você tem que verificar a string tablename contra uma lista de nomes aprovados.
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;
  ...

Essa é a única maneira de fazer isso, que eu saiba.

BTW Seu código original tem um erro:
query.SQL.Text := 'select * from table_name where name=:Name where id=:ID'; 

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

Você não pode ter dois where está em uma (sub)consulta