防止 SQL 注入

Jar*_*rgs 3 sql-server sql-injection

我知道这是非常危险的:

EXEC sp_executesql 'SELECT * FROM ' + @Table
Run Code Online (Sandbox Code Playgroud)

但是,这对 SQL 注入安全吗?

IF EXISTS(SELECT * FROM information_schema.tables WHERE TABLE_NAME = @Table) BEGIN
    EXEC sp_executesql 'SELECT * FROM ' + @Table
END
Run Code Online (Sandbox Code Playgroud)

Aar*_*and 5

这里仍有注入的潜力。让我们假设:

  1. 有人有能力在这个数据库中创建表,但不能删除它们
  2. 有人有能力调用这个程序
  3. 该过程以提升的用户身份运行

该人可以调用此过程以从 中获取结果foo,但同时创建一个名为 的表[foo;drop table bar],然后foo;drop table bar作为参数值传入。它会通过你的检查,然后你会盲目地执行它。他们得到结果,foo但他们也会删除 table bar

现在,这是一个非常人为的场景,您可能并不担心内部人员删除表,但他们也可以使用它来利用他们无权访问的数据,例如他们可以创建一个名为的表[foo;SELECT name,salary FROM dbo.Employees;]并最终有两个结果集,一个包含您可能不应该让他们看到的数据。

如果不同模式中存在具有相同名称的表,则还可能从错误的表中获取数据。在创建或引用对象时,始终,始终,始终使用架构前缀:

最后,不要使用INFORMATION_SCHEMA. 目录视图和元数据功能更加完整、最新和可靠:

我可能会这样做(为了简单起见,我将假设您的所有表都在 dbo 中):

DECLARE @table SYSNAME; -- procedure parameter, right?

DECLARE @sql NVARCHAR(MAX);
IF OBJECT_ID(N'dbo.' + QUOTENAME(@table), N'U') IS NOT NULL
BEGIN
  SET @sql = N'SELECT * FROM dbo.' + QUOTENAME(@table) + ';';
  EXEC sp_executesql @sql;
END
Run Code Online (Sandbox Code Playgroud)

这样,即使他们通过foo;drop table barfoo;select name,salary from dbo.employees作为表名,整个字符串也会被方括号包围,因此可能发生的最糟糕的事情是他们将从他们创建的表中获得结果,而不是任何其他表或更糟。

而且我会确保该过程以该用户身份运行,而不是升级使用EXECUTE AS(正确权限配置的常见绕过)。另见: