Delphi - 防止SQL注入

发布于 2024-11-06 20:10:42 字数 489 浏览 1 评论 0原文

我需要保护应用程序免受 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

×眷恋的温暖 2024-11-13 20:10:42

安全

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;删除表名;
导致执行以下查询。

select * from table_name where name=name; Drop table_name;

不安全

var Username: string;
...
query.SQL.Text := 'select * from table_name where name='''+ UserName+'''';

因为如果用户名是'或(1=1);删除表名; --
它将产生以下查询:

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;
  ...

据我所知,这是唯一的方法。

顺便说一句,您的原始代码有一个错误:

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

Safe

query.SQL.Text := 'select * from table_name where name=:Name';

This code is safe because you are using parameters.
Parameters are always safe from SQL-injection.

Unsafe

var Username: string;
...
query.SQL.Text := 'select * from table_name where name='+ UserName;

Is unsafe because Username could be name; Drop table_name;
Resulting in the following query being executed.

select * from table_name where name=name; Drop table_name;

Also Unsafe

var Username: string;
...
query.SQL.Text := 'select * from table_name where name='''+ UserName+'''';

Because it if username is ' or (1=1); Drop Table_name; --
It will result in the following query:

select * from table_name where name='' or (1=1); Drop Table_name; -- '

But this code is safe

var id: integer;
...
query.SQL.Text := 'select * from table_name where id='+IntToStr(id);

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

query:= 'SELECT * FROM :dynamic_table '; {doesn't work}
query:= 'SELECT * FROM '+tableName;      {works, but is unsafe}

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.

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;
  ...

That's the only way to do this, that I know of.

BTW Your original code has an error:

query.SQL.Text := 'select * from table_name where name=:Name where id=:ID'; 

Should be

query.SQL.Text := 'select * from table_name where name=:Name and id=:ID'; 

You cannot have two where's in one (sub)query

野稚 2024-11-13 20:10:42

如果您允许用户影响将绑定到带有占位符的 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.

波浪屿的海角声 2024-11-13 20:10:42

这可以保证我的最低安全级别吗?

是的,参数化查询应该可以保护您免受 SQL 注入的影响,这很容易测试。只需在 name 变量中输入一些危险的字符串,然后看看会发生什么。通常您应该返回 0 行而不是错误。

This will assure me a minimum of security level?

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文