Delphi - 防止SQL注入
我需要保护应用程序免受 SQL 注入。应用程序使用ADO连接到Oracle,并搜索用户名和密码进行身份验证。
从我到目前为止所读到的内容来看,最好的方法是使用参数,而不是将整个 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 之外的任何其他组件。
I need to protect an application from SQL injection. Application is connecting to Oracle, using ADO, and search for the username and password to make the authentication.
From what I've read until now, the best approach is by using parameters, not assigning the entire SQL as string. Something like this:
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;
Also, I'm thinking to verify the input from user, and to delete SQL keywords like delete,insert,select,etc...Any input character different than normal ASCII letters and numbers will be deleted.
This will assure me a minimum of security level?
I do not want to use any other components than Delphi 7 standard and Jedi.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
安全
此代码是安全的,因为您正在使用参数。
参数始终不会受到 SQL 注入的影响。
不安全
不安全,因为用户名可能是
name;删除表名;
导致执行以下查询。
也不安全
因为如果用户名是
'或(1=1);删除表名; --
它将产生以下查询:
但是此代码是安全的
因为
IntToStr()
只接受整数,因此不能通过这种方式将 SQL 代码注入到查询字符串中,只能数字(这正是您想要的,因此是允许的)但我想做一些无法使用参数完成的事情
参数只能用于值。它们不能替换字段名称或表名称。
因此,如果要执行此查询,
第一个查询会失败,因为不能使用表或字段名称的参数。
第二个查询不安全,但这是完成此操作的唯一方法。
如何保持安全?
您必须根据批准的名称列表检查字符串
tablename
。据我所知,这是唯一的方法。
顺便说一句,您的原始代码有一个错误:
应该是
您不能在一个(子)查询中有两个
where
Safe
This code is safe because you are using parameters.
Parameters are always safe from SQL-injection.
Unsafe
Is unsafe because Username could be
name; Drop table_name;
Resulting in the following query being executed.
Also Unsafe
Because it if username is
' or (1=1); Drop Table_name; --
It will result in the following query:
But this code is safe
Because
IntToStr()
will only accept integers so no SQL code can be injected into the query string this way, only numbers (which is exactly what you want and thus allowed)But I want to do stuff that can't be done with parameters
Parameters can only be used for values. They cannot replace field names or table names.
So if you want to execute this query
The first query fails because you cannot use parameters for table or field names.
The second query is unsafe but is the only way this this can be done.
How to you stay safe?
You have to check the string
tablename
against a list of approved names.That's the only way to do this, that I know of.
BTW Your original code has an error:
Should be
You cannot have two
where
's in one (sub)query如果您允许用户仅影响将绑定到带有占位符的 sql 命令文本中的参数值,那么您实际上不需要检查用户输入的内容:避免的最简单方法正如您提到的,SQL 注入是为了避免连接 SQL,并且使用绑定变量(或调用过程)可以做到这一点(它还有一个优点 - 里程/相关性取决于数据库 - 允许引擎重复使用查询计划) 。
如果您使用 Oracle,那么您需要有一个不使用绑定变量的充分理由:Tom Kyte 在他的网站上有大量关于这方面的好信息 http://asktom.oracle.com。只需在搜索框中输入“绑定变量”即可。
If you allow the user to influence only the value of parameters that will be bound into an sql command text with placeholders, then you don't really need to inspect what the user enters: the simplest way to avoid SQL injection, as you mention, is to avoid concatenated SQL, and using bound variables (or calling procedures) does this (it also has the advantage - mileage/relevance depends on the database - of allowing the engine to re-use query plans).
If you are using Oracle, then you need to have a really good reason for not using bound variables: Tom Kyte has a ton of good information about this on his site http://asktom.oracle.com. Just enter "bound variables" in the search box.
是的,参数化查询应该可以保护您免受 SQL 注入的影响,这很容易测试。只需在
name
变量中输入一些危险的字符串,然后看看会发生什么。通常您应该返回 0 行而不是错误。Yes parametrized queries should protect you from SQL injection which would be easy to test. Simply input some dangerous string in the
name
variable and see what happens. Normally you should get 0 rows returned and not an error.