7

当我尝试使用包含撇号的值执行下面的 PostgreSQL 查询时,我遇到了第一个 sql 转义错误(早就应该)了。O'Brien, 使用 FreePascal 和 Lazarus

SQL.Add(format('select * from zones where upper(zn_name) >=  %s and upper(zn_name) < %s order by zn_name',[sQuote(zoneMin), sQuote(zoneMax)]));

在上面的查询中,SQuote 是一个将字符串包裹在单引号中的函数。是否有一些标准库用于清理 Lazarus/FreePascal 或 Delphi 的 SQL 查询参数?

4

1 回答 1

18

您的应用程序容易受到称为SQL 注入的严重安全问题的影响。请参阅http://bobby-tables.com/

当然,O'Brian会导致错误,但是呢');DROP SCHEMA public;--?或者');DELETE FROM users;--?第一个不应该工作,因为您的应用程序不应该超级用户或拥有表的用户身份运行,但很少有应用程序设计人员努力实际这样做并且经常在生产中运行特权用户。第二种适用于大多数应用程序;详情见文末。

最简单和最好的预防措施是在您的客户端库中使用参数化语句* 。请参阅Delpi 的此示例:

To use a prepared statement, do something like this:

query.SQL.Text := 'update people set name=:Name where id=:ID';
query.Prepare;
query.ParamByName( 'Name' ).AsString := name;
query.ParamByName( 'ID' ).AsInteger := id;
query.ExecSQL;

(我从未使用过 Delphi,最后一次编写 Pascal 代码是在 1995 年;我只是引用给出的示例)。

您目前正在做的是参数的字符串插值。这是非常危险的。只有当你有一个强大的引用 SQL 文字的函数时,它才能安全地完成,这个函数不仅可以在每一端加上引号,还可以处理其他转义、引号加倍等。这是最后的方法;强烈建议使用参数化语句。


这是我上面给出的示例的扩展。假设您正在通过用户名执行一个非常普通的用户插入,其中“Fred”是客户端输入的示例用户名:

INSERT INTO users ( user_name ) VALUES ('Fred');

现在一些不愉快的人发送用户名');DELETE FROM users;--。突然你的应用程序正在运行:

INSERT INTO users ( user_name ) VALUES ('');DELETE FROM users;--');

展开时是:

INSERT INTO users ( user_name ) VALUES ('');
DELETE FROM users;
--');

或者换句话说,插入一个空字符串(尽管他们可以很容易地放入一个完全有效的用户名),然后是一个DELETE FROM users;语句 - 删除所有行users- 然后是一个什么都不做的评论。啪啪啪。你的数据就到这里了。


*参数化语句有时被错误地称为预准备语句。这是不正确的,因为准备好的语句不一定是参数化的,而参数化的语句也不一定是准备好的。由于许多语言的数据库接口不提供使用参数化语句而不使用预准备语句的方法,因此出现了混淆。

于 2012-11-01T04:45:45.430 回答