Delphi - предотвратить SQL-инъекцию - PullRequest
27 голосов
/ 14 мая 2011

Мне нужно защитить приложение от внедрения 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, такие как delete, insert, select и т.д ... Любой символ ввода, отличный от обычных букв ASCIIи номера будут удалены.

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

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

Ответы [ 3 ]

44 голосов
/ 14 мая 2011

Сейф

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

12 голосов
/ 14 мая 2011

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

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

6 голосов
/ 14 мая 2011

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...