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 строк, а не ошибку.