且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Delphi - 防止 SQL 注入

更新时间:2023-12-02 09:42:16

安全

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

此代码是安全的,因为您使用的是参数.
参数对于 SQL 注入始终是安全的.

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

不安全

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

不安全,因为用户名可能是 name;删除 table_name;导致执行以下查询.

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;

不安全

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

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

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

但是这个密码是安全的

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

因为 IntToStr() 只接受整数,所以不能通过这种方式将 SQL 代码注入到查询字符串中,只有数字 (这正是你想要的,因此被允许)

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)

但是我想做一些参数做不到的事情

参数只能用于值.它们不能替换字段名或表名.所以如果你想执行这个查询

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?

您必须对照已批准的名称列表检查字符串 tablename.

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.

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

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

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