Delphi-предотвращение SQL-инъекций

Мне нужно защитить приложение от SQL-инъекции. Приложение подключается к Oracle, используя ADO, и ищет имя пользователя и пароль для аутентификации.

из того, что я читал до сих пор, лучший подход-использовать параметры, а не назначать весь SQL как строку. Что-то вроде этого:--2-->

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;

кроме того, я думаю проверить ввод от пользователя и удалить ключевые слова SQL,такие как delete,insert,select и т. д...Любой входной символ в отличие от обычных ASCII буквы и цифры будут удалены.

Это обеспечит мне минимальный уровень безопасности?

Я не хочу использовать какие-либо другие компоненты, кроме Delphi 7 standard и Jedi.

3 ответов


безопасное

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

этот код безопасен, потому что вы используете параметры.
Параметры всегда безопасны от SQL-инъекции.

небезопасных

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

- это небезопасно, потому что имя пользователя может быть name; Drop table_name; В результате выполняется следующий запрос.

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

и небезопасных

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

потому что это если имя пользователя ' or (1=1); Drop Table_name; -- Это приведет к следующему запрос:

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

но этот код безопасен

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

, потому что IntToStr() будет принимать только целые числа, поэтому код SQL не может быть введен в строку запроса таким образом, только числа (что именно то, что вы хотите и, таким образом, разрешено)

но я хочу делать вещи, которые нельзя сделать с параметрами

параметры могут использоваться только для значений. Они не могут заменить имена полей или таблиц. Так если вы хотите выполнить этот запрос

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

первый запрос завершается неудачно, так как нельзя использовать параметры для имен таблиц или полей.
Второй запрос небезопасен, но это единственный способ сделать это.
Как вам оставаться в безопасности?

вы должны проверить строку tablename со списком разрешенных имен.

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;
  ...

это единственный способ сделать это, который я знаю.

BTW ваш исходный код имеет ошибка:

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

должно быть

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

вы не можете иметь два whereв одном (sub)запросе


Если вы позволяете пользователю влиять только значение параметров, которые будут привязаны к тексту команды sql с заполнителями, тогда вам действительно не нужно проверять, что вводит пользователь: самый простой способ избежать SQL-инъекции, как вы упомянули, - это избежать конкатенированного SQL, и использование связанных переменных (или вызывающих процедур) делает это (это также имеет преимущество-пробег / релевантность зависит от базы данных-позволяя движку повторно использовать запрос планировавший.)

Если вы используете Oracle, то у вас должна быть действительно веская причина для не использование связанных переменных: том Кайт имеет массу хорошей информации об этом на своем сайте http://asktom.oracle.com. Просто введите "связанные переменные" в поле поиска.


Это обеспечит мне минимальный уровень безопасности?

да параметризованные запросы должны защитить вас от SQL-инъекций, которые было бы легко протестировать. Просто введите опасную строку в name переменной и посмотреть, что происходит. Обычно вы должны получить 0 строк, а не ошибку.