Подтвердить что ты не робот

Delphi - предотвращение внедрения SQL

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

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

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, такие как удаление, вставка, выбор и т.д. Любой символ ввода, отличный от обычных букв и цифр ASCII, будет удален.

Это обеспечит мне минимум уровня безопасности?

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

4b9b3361

Ответ 1

Безопасный

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 в одном (под) запросе

Ответ 2

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

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

Ответ 3

Это обеспечит мне минимум уровня безопасности?

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