如何保护该函数免受 SQL 注入?

发布于 2024-08-13 17:46:01 字数 223 浏览 5 评论 0原文

public static bool TruncateTable(string dbAlias, string tableName)
{
    string sqlStatement = string.Format("TRUNCATE TABLE {0}", tableName);
    return ExecuteNonQuery(dbAlias, sqlStatement) > 0;
}
public static bool TruncateTable(string dbAlias, string tableName)
{
    string sqlStatement = string.Format("TRUNCATE TABLE {0}", tableName);
    return ExecuteNonQuery(dbAlias, sqlStatement) > 0;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(11

高冷爸爸 2024-08-20 17:46:01

对抗 SQL 注入的最常见建议是使用 SQL 查询参数(该线程上的几个人都建议这样做)。

在本例中这是错误的答案。您不能在 DDL 语句中对表名使用 SQL 查询参数。

SQL 查询参数只能用于代替 SQL 表达式中的文字值。这是每个 SQL 实现的标准。

当您有表名时,我建议防止 SQL 注入是根据已知表名列表验证输入字符串。

您可以从 INFORMATION_SCHEMA 获取有效表名的列​​表:

SELECT table_name 
FROM INFORMATION_SCHEMA.Tables 
WHERE table_type = 'BASE TABLE'
  AND table_name = @tableName

现在您可以将输入变量作为 SQL 参数传递给此查询。如果查询未返回任何行,则您知道输入无效,无法用作表。如果查询返回一行,则它匹配,因此您可以更放心地使用它。

您还可以根据您定义为可以让应用程序截断的特定表列表来验证表名称,如 @John Buchanan 建议

即使在验证 tableName 作为 RDBMS 中的表名称存在之后,我也建议对表名称进行分隔,以防万一您使用带有空格或特殊字符的表名称。在 Microsoft SQL Server 中,默认标识符分隔符是方括号:

string sqlStatement = string.Format("TRUNCATE TABLE [{0}]", tableName);

现在,只有当 tableName 与真实表匹配时,您才会面临 SQL 注入的风险,并且您实际上在表名称中使用了方括号!

The most common recommendation to fight SQL injection is to use an SQL query parameter (several people on this thread have suggested it).

This is the wrong answer in this case. You can't use an SQL query parameter for a table name in a DDL statement.

SQL query parameters can be used only in place of a literal value in an SQL expression. This is standard in every implementation of SQL.

My recommendation for protecting against SQL injection when you have a table name is to validate the input string against a list of known table names.

You can get a list of valid table names from the INFORMATION_SCHEMA:

SELECT table_name 
FROM INFORMATION_SCHEMA.Tables 
WHERE table_type = 'BASE TABLE'
  AND table_name = @tableName

Now you can pass your input variable to this query as an SQL parameter. If the query returns no rows, you know that the input is not valid to use as a table. If the query returns a row, it matched, so you have more assurance you can use it safely.

You could also validate the table name against a list of specific tables you define as okay for your app to truncate, as @John Buchanan suggests.

Even after validating that tableName exists as a table name in your RDBMS, I would also suggest delimiting the table name, just in case you use table names with spaces or special characters. In Microsoft SQL Server, the default identifier delimiters are square brackets:

string sqlStatement = string.Format("TRUNCATE TABLE [{0}]", tableName);

Now you're only at risk for SQL injection if tableName matches a real table, and you actually use square brackets in the names of your tables!

客…行舟 2024-08-20 17:46:01

据我所知,不能使用参数化查询来执行DDL语句/指定表名,至少在Oracle或Sql Server中不能。如果我必须有一个疯狂的 TruncateTable 函数,并且必须能够避免 SQL 注入,我会做的就是创建一个存储过程来检查输入是否是可以安全截断的表。


-- Sql Server specific!
CREATE TABLE TruncableTables (TableName varchar(50))
Insert into TruncableTables values ('MyTable')

go

CREATE PROCEDURE MyTrunc @tableName varchar(50)
AS
BEGIN

declare @IsValidTable int
declare @SqlString nvarchar(50)
select @IsValidTable = Count(*) from TruncableTables where TableName = @tableName

if @IsValidTable > 0
begin
 select @SqlString = 'truncate table ' + @tableName
 EXECUTE sp_executesql @SqlString
end
END

As far as I know, you can't use parameterized queries to perform DDL statements/ specify table names, at least not in Oracle or Sql Server. What I would do, if I had to have a crazy TruncateTable function, that had to be safe from sql injection would be to make a stored procedure that checks that the input is a table that is safe to truncate.


-- Sql Server specific!
CREATE TABLE TruncableTables (TableName varchar(50))
Insert into TruncableTables values ('MyTable')

go

CREATE PROCEDURE MyTrunc @tableName varchar(50)
AS
BEGIN

declare @IsValidTable int
declare @SqlString nvarchar(50)
select @IsValidTable = Count(*) from TruncableTables where TableName = @tableName

if @IsValidTable > 0
begin
 select @SqlString = 'truncate table ' + @tableName
 EXECUTE sp_executesql @SqlString
end
END
美煞众生 2024-08-20 17:46:01

如果您允许用户定义的输入通过表名变量渗透到此函数中,我不认为 SQL 注入是您唯一的问题。

更好的选择是通过自己的安全连接运行此命令,并且根本不授予它 SELECT 权限。 TRUNCATE 运行所需的只是 ALTER TABLE 权限。如果您使用的是 SQL 2005 以上版本,您还可以尝试使用内部包含 EXECUTE AS 的存储过程。

If you're allowing user-defined input to creep into this function via the tablename variable, I don't think SQL Injection is your only problem.

A better option would be to run this command via its own secure connection and give it no SELECT rights at all. All TRUNCATE needs to run is the ALTER TABLE permission. If you're on SQL 2005 upwards, you could also try using a stored procedure with EXECUTE AS inside.

最冷一天 2024-08-20 17:46:01
CREATE OR REPLACE PROCEDURE truncate(ptbl_name IN VARCHAR2) IS
  stmt VARCHAR2(100);
BEGIN
  stmt := 'TRUNCATE TABLE '||DBMS_ASSERT.SIMPLE_SQL_NAME(ptbl_name);
  dbms_output.put_line('<'||stmt||'>');
  EXECUTE IMMEDIATE stmt;
END;
CREATE OR REPLACE PROCEDURE truncate(ptbl_name IN VARCHAR2) IS
  stmt VARCHAR2(100);
BEGIN
  stmt := 'TRUNCATE TABLE '||DBMS_ASSERT.SIMPLE_SQL_NAME(ptbl_name);
  dbms_output.put_line('<'||stmt||'>');
  EXECUTE IMMEDIATE stmt;
END;
﹏半生如梦愿梦如真 2024-08-20 17:46:01

使用存储过程。任何像样的数据库库(我使用的是 MS Enterprise Library)都可以正确处理转义字符串参数。

另外,重新:参数化查询:我宁愿不必重新部署我的应用程序来修复数据库问题。将查询作为文字字符串存储在源中会增加维护复杂性。

Use a stored procedure. Any decent db library (MS Enterprise Library is what I use) will handle escaping string parameters correctly.

Also, re:parameterized queries: I prefer to NOT have to redeploy my app to fix a db issue. Storing queries as literal strings in your source increases maintenance complexity.

韶华倾负 2024-08-20 17:46:01

查看此链接

此代码是否可以防止 SQL 注入?

删除不需要的内容来自表名字符串。

我认为您不能使用参数查询作为表名。

Have a look at this link

Does this code prevent SQL injection?

Remove the unwanted from the tableName string.

I do not think you can use param query for a table name.

べ映画 2024-08-20 17:46:01

还有一些其他帖子将有助于 SQL 注入,因此我将投票支持这些帖子,但另一件事需要考虑的是您将如何处理此操作的权限。如果您授予用户 db+owner 或 db_ddladmin 角色以便他们可以截断表,那么仅仅避免标准 SQL 注入攻击是不够的。黑客可以发送其他可能有效但您不希望被截断的表名称。

如果您向允许截断的特定表上的用户授予 ALTER TABLE 权限,那么您的情况会好一点,但仍然超出了我在正常环境中允许的范围。

通常,在正常的日常应用程序使用中不会使用 TRUNCATE TABLE。它用于 ETL 场景或数据库维护期间。我想象它会在前端应用程序中使用的唯一情况是,如果您允许用户加载特定于该用户的表以用于加载目的,但即使如此,我也可能会使用不同的解决方案。

当然,在不知道您使用它的具体原因的情况下,我不能断然地说您应该重新设计,但如果我作为 DBA 收到这样的请求,我会问开发人员很多问题。

There are some other posts which will help with the SQL injection, so I'll upvote those, but another thing to consider is how you will be handling permissions for this. If you're granting users db+owner or db_ddladmin roles so that they can truncate tables then simply avoiding standard SQL injection attacks isn't sufficient. A hacker can send in other table names which might be valid, but which you wouldn't want truncated.

If you're giving ALTER TABLE permissions to the users on the specific tables that you will allow to be truncated then you're in a bit better shape, but it's still more than I like to allow in a normal environment.

Usually TRUNCATE TABLE isn't used in normal day-to-day application use. It's used for ETL scenarios or during database maintenance. The only situation where I might imagine it would be used in a front-facing application would be if you allowed users to load a table which is specific for that user for loading purposes, but even then I would probably use a different solution.

Of course, without knowing the specifics around why you're using it, I can't categorically say that you should redesign, but if I got a request for this as a DBA I'd be asking the developer a lot of questions.

も星光 2024-08-20 17:46:01

使用参数化查询。

Use parameterized queries.

甜尕妞 2024-08-20 17:46:01

在这个具体示例中,仅当表名来自外部源时,您才需要防止 SQL 注入。

你为什么会允许这种事发生?
如果您允许某些外部实体(最终用户、其他系统,什么?)
要命名要删除的表,为什么不直接授予他们管理员权限。

如果您要创建和删除表以便为最终用户提供某些功能,
不要让他们直接提供数据库对象的名称。
除了 SQL 注入之外,您还会遇到名称冲突等问题。
相反,您自己生成真实的表名称(例如 DYNTABLE_00001、DYNTABLE_00002,...)并保留一个将它们连接到用户提供的名称的表。


关于为 DDL 操作生成动态 SQL 的一些注意事项:

  • 在大多数 RDBMS 中,您必须使用动态 SQL 并将表名称作为文本插入。
    要格外小心。

  • 使用带引号的标识符(MS SQL Server 中为 [],所有符合 ANSI 的 RDBMS 中为 "")。
    这将更容易避免由无效名称引起的错误。

  • 在存储过程中执行此操作,并检查所有引用的对象是否有效。

  • 不要做任何不可挽回的事情。例如,不要自动删除表。
    您可以将它们标记为删除并向您的 DBA 发送电子邮件。
    备份后她会删除它们。

  • 如果可以的话,避免它。如果做不到,请尽您所能尽量减少他人的权利
    普通用户将拥有的(非动态)表。

In this concrete example you need protection from SQL injection only if table name comes from external source.

Why would you ever allow this to happen?
If you are allowing some external entity (end user, other system, what?)
to name a table to be dropped, why won't you just give them admin rights.

If you are creating and removing tables to provide some functionality for end user,
don't let them provide names for database objects directly.
Apart from SQL injection, you'll have problems with name clashes etc.
Instead generate real table names yourself (e.g DYNTABLE_00001, DYNTABLE_00002, ...) and keep a table that connects them to the names provided by user.


Some notes on generating dynamic SQL for DDL operations:

  • In most RDBMS-s you'll have to use dynamic SQL and insert table names as text.
    Be extra careful.

  • Use quoted identifiers ([] in MS SQL Server, "" in all ANSI compliant RDBMS).
    This will make avoiding errors caused by invalid names easier.

  • Do it in stored procedures and check if all referenced objects are valid.

  • Do not do anything irreversible. E.g. don't drop tables automatically.
    You can flag them to be dropped and e-mail your DBA.
    She'll drop them after the backup.

  • Avoid it if you can. If you can't, do what you can to minimize rights to other
    (non-dynamic) tables that normal users will have.

再见回来 2024-08-20 17:46:01

您可以使用 SQLParameter 传入 tableName价值。据我所知和测试,SQLParameter 负责所有参数检查,从而禁用注入的可能性。

You could use SQLParameter to pass in tableName value. As far as I know and tested, SQLParameter takes care of all parameter checking and thus disables possibility of injection.

一抹微笑 2024-08-20 17:46:01

如果您不能使用参数化查询(并且您应该)...将 ' 的所有实例简单替换为 '' 应该可以。

string sqlStatement = string.Format("TRUNCATE TABLE {0}", tableName.Replace("'", "''")); 

If you can't use parameterized queries (and you should) ... a simple replace of all instances of ' with '' should work.

string sqlStatement = string.Format("TRUNCATE TABLE {0}", tableName.Replace("'", "''")); 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文