插入时的SQL注入攻击

35

我已在公司内网创建了一个小型调查网页。该网页无法从外部访问。

该表单只包含几个单选按钮和一个评论框。

我想要遵循良好的编码实践,并希望防范SQL注入攻击。

插入语句中的文本框注释是否可能会导致SQL注入攻击?如果是,如何使用.NET 2.0来避免它?


附加信息:当您构建一个网页时,不要仅仅关注 SQL 注入。在将文本插入到数据库之前,请检查文本的 XSS 危险性。所有输出代码是否都通过 Server.HtmlEncode(...) 进行了安全处理? - Michael Piendl
8个回答

65

注入可以发生在任何未正确运行的 SQL 语句上。

举个例子,假设您的评论表有两个字段,一个是整数 ID,另一个是评论字符串。那么您应该这样进行 INSERT

 INSERT INTO COMMENTS VALUES(122,'I like this website');

考虑有人输入以下评论:

'); DELETE FROM users; --

如果你直接将注释字符串放入SQL语句中而没有任何处理,那么这可能会将你的单个INSERT语句变成以下两个语句,然后是注释:

INSERT INTO COMMENTS VALUES(123,''); DELETE FROM users; -- ');
这将从你的users表中删除所有内容。有些人愿意花一整天时间通过试错和各种技巧来找到正确的表名以便清空。这里有一个关于如何执行SQL注入攻击的描述。 为了防止这种情况发生,你需要使用参数化SQL语句
而且这不仅仅是出于安全原因。例如,如果你简单地创建SQL语句,以下评论可能会导致问题:
I'm just loving this website

由于 SQL 将撇号解释为闭合引号,这将导致 SQL 语法错误。


3
关于撇号的问题,你提供了很好的建议。我之前一直使用string.replace方法,但现在看来这个方法更加简便易行。 - Brad
1
即使是一个名字,如果不作为参数处理,也会引起问题,例如O'Tool、O'Rourke。 - Martin
4
我们有一个名叫Ja'Net的女孩加入了我的公司,这真的搞乱了一些事情。但是大部分代码都是在我来之前编写的。 - Aaron Smith
我一直在寻找关于插入语句的SQL注入相关内容,终于找到了!谢谢你! - Sylca

28

使用参数化查询,这样文本会自动为您加上引号。

SqlCommand command = connection.CreateCommand();
command.CommandText = "insert into dbo.Table (val1,val2,txt) values (@val1,@val2,@txt)";
command.AddParameterWithValue( "val1", value1 );
command.AddParameterWithValue( "val2", value2 );
command.AddParameterWithValue( "txt", text );

...

3

每当你将查询返回到数据库时,都可能发生SQL注入。这里是一个简单的演示:

SQL注入解释

在.NET中,关键是像Dave Webb所给出的那样处理。它将整个字符串作为一个参数进行提交,处理SQL Server可能解释的所有字符,以更改查询或附加其他命令来防止注入尝试。

还应该指出,SQL注入可能发生在任何应用程序上,而不仅仅是Web应用程序。内部攻击通常对组织造成的损失最大。人们不能安全地认为攻击不会起源于内部。


1

除了使用预处理语句和参数而不是将字符串连接到SQL中,您还应该执行以下操作:

  1. 在服务器端验证和格式化用户输入。客户端验证和限制很容易被绕过,例如使用WebScarab工具或欺骗您的表单。

  2. 为数据库用户帐户配置适当的权限。Web应用程序应在数据库中使用单独的帐户或角色,并将权限限制为运行应用程序所需的仅表、视图和过程。确保用户没有对系统表的选择权限

  3. 从用户隐藏详细的错误消息,并为对象使用不太常见的名称。让我惊讶的是,有多少次你可以确定服务器类型(Oracle、MySQL、SQL Server),并在错误消息中找到基本模式信息,然后从名为“user(s)”、“employee(s)”的表中获取信息。如果您还没有像(2)中设置权限,而我可以确定您的服务器类型,那么您会面临像这样的SQL Server语句:

    SELECT table_name FROM information_schema.table

    EXECUTE sp_help foundTableName


0

是的,这种情况可能发生。最简单的防范方法是使用预处理语句而不是手动构建 SQL。

因此,不要这样做:

String sql = 
 String.Format("INSERT INTO mytable (text_column) VALUES ( '{0}' )",
   myTextBox.Text); // Unsafe!

你可以这样做:
String sql = "INSERT INTO mytable (text_column) VALUES ( ? )"; // Much safer

然后将文本框的文本添加为DbCommand的参数,它会自动转义并替换SQL中的“?”。


0

使用预处理语句来防止 SQL 注入。占位符(?)的使用完全消除了 SQL 注入漏洞。 例如 String sql=Select * from user_table where username='+request.getparameter("username")+'; statement.executeQuery(sql);

上述语句容易受到 SQL 注入攻击。

为了使其免受 SQL 注入攻击,请使用以下代码片段:

String sql=Select * from user_table where username=?; statement.setString(1,username);


-1

可以的。假设客户端发送了这个:

OR 1 = 1

这可能会对你非常痛苦

  SELECT * FROM admin WHERE name = @name AND password = @password

您可以通过以下方式来防止此类问题:


这个问题明确涉及到INSERT语句。 - David Webb
返回已翻译的文本:true。但也许列表有帮助。 - boj

-4

防范SQL注入的最简单方法是使用参数和存储过程,而不是构建SQL语句来运行(在C#或SQL Server内部)。

然而,我并不完全确定你是否应该花时间处理这个问题,除非这是你公司的政策,因为它在内部发生的可能性最小,如果确实发生了,我希望你能立即知道是谁造成的。


当然,不满的员工永远不会试图破坏你公司的数据库。你总是需要关注安全并遵循最佳实践。 - tvanfosson
我不同意。这是一个内部网页,任何离职员工都不应该能够访问。此外,我猜测(或者肯定希望)所有内部流量都被记录了下来。安全需求必须与其他标准一起评估,并且在许多情况下可能无法证明其合理性。 - Bravax
谁说你必须是一名前雇员才能感到不满?良好的安全措施是预防损害,而不是事后指责。在这种情况下,使用参数化查询的成本甚至不是很高。手动构建查询时,这应该是常态。 - tvanfosson
1
我认为不允许用户(无意或有意地)删除您的数据始终是一种安全需求。为什么不对输入进行净化?通过避免净化,一个人可能会获得什么收益?这并不意味着我们必须要付出双倍的努力才能做到正确。我没有给你点踩,但我不同意。 - Learning
1
@TVanfosson,内部员工可能会不满,但这是一项内部调查。确保不满的员工不能走出自己的路并破坏它是否值得呢? 我同意这应该成为常态,但像这样的安全措施不能强加给人们。必须权衡其他成本。 - Bravax
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接