如何在C#for SqlServer中转义简单的SQL查询


77

我使用期望使用SQL字符串的API。我接受用户输入,对其进行转义并将其传递给API。用户输入非常简单。它要求列值。像这样:

string name = userInput.Value;

然后,我构造一个SQL查询:

string sql = string.Format("SELECT * FROM SOME_TABLE WHERE Name = '{0}'",
                           name.replace("'", "''"));

这样够安全吗?如果不是,是否有一个简单的库函数使列值安全:

string sql = string.Format("SELECT * FROM SOME_TABLE WHERE Name = '{0}'",
                           SqlSafeColumnValue(name));

该API使用SQLServer作为数据库。


参数化它!一个谷歌搜索的“SQL注入”编辑SO的:为了响应塞瓦·阿列克谢耶夫,与八字注入SO回答
GBN

3
需要使用参数。
SLaks

2
@SLaks,很明显,API不允许这样做。也许他需要一个新的API。
C. Ross,2010年

3
如果您解释了为什么不能/不使用参数,@ sri会得到更好的答案。
Foole 2010年

有没有办法用列表参数化查询? SELECT [Name], [Value] FROM [SomeTable] WHERE [Name] IN (@ListOfNames) 我的意思是其他方式,而不是 var listParNames = listNames.Select(name => { var pname = string.Format("@n{0}", cmd.Parameters.Count); cmd.Parameters.AddWithValue(pname, name); return pname; }); cmd.CommandText = string.Format("SELECT [Name], [Value] FROM [SomeTable] WHERE [Name] in ({0})", string.Join(",", listParNames.ToArray())); 直接使用cmd.Parameters.AddWithValue("@ListOfNames", listNames.ToArray());
mizuki nakeshu 2014年

Answers:


137

由于不能使用SqlParameter,因此只需在字符串文字中用'(用两个单引号而不是一个双引号)替换'。而已。

致低俗人士:重新阅读问题的第一行。“使用参数”也是我的直觉。

编辑:是的,我知道SQL注入攻击。如果您认为此报价容易受到影响,请提供一个有效的反例。我认为不是。


13
罗伯特(Robert)之后有一点点'。这就是如何。如果正确引用,则Bobby的非正统名称将全部存储在数据库中。
塞瓦·阿列克谢耶夫

45
Seva Alekseyev非常感谢您阅读并尝试回答我的问题。感谢您不向我讲授“最佳做法”。并感谢您不尝试“教育我”真的,谢谢!
sc45

12
嗯,作为记录,我仍然认为应该采用参数:)但是,我从事这项业务已经足够长的时间了,以了解设计中存在约束的情况。去过也做过。
塞瓦·阿列克谢耶夫

13
@Seva尽管每个人都知道上面的代码有待注入,但有时您会被束缚在一个API上,而该API不允许您遵循最佳实践。程序员常常担心那些不在特定任务关注范围之内的东西。对特定问题的好答案。
基思·阿德勒

9
好答案!我们需要像您这样的更多有用的人,而不需要光顾和教育的人!我投票给你,投票给另一个无知的家伙
Christian

0

我正在使用动态sql(我可以听到射击队正在加载步枪)来进行搜索,但是只要用户搜索姓氏为“ O'Reilly”的人,它就会中断。

我设法找出一种解决方法(请阅读“ hack”):

在sql中创建了一个标量值函数,用两个单引号替换了一个单引号,有效地转义了有问题的单引号,因此
“ ... Surname LIKE'%O'Reilly%'AND ...”变为“ ... Surname就像'%O''Reilly%'AND ...“

每当我怀疑字段可以包含单引号(即:firstname,lastname)时,就会从sql中调用此函数。

CREATE FUNCTION [dbo].[fnEscapeSingleQuote]
    (@StringToCheck NVARCHAR(MAX))
RETURNS NVARCHAR(MAX)
AS
BEGIN
    DECLARE @Result NVARCHAR(MAX)
    SELECT @Result = REPLACE(@StringToCheck, CHAR(39), CHAR(39) + CHAR(39))
    RETURN @Result
END

不是很优雅或高效,但是当您紧要关头时,它就可以工作。


0

当需要在短时间内以最小的破损风险和最少的测试来解决大量临时SQL中的'问题时,可能希望用'代替'而不是进行参数化。


0

SqlCommand和Entity Framework的使用exec sp_executesql...

因此,大概可以用您自己的转义模式替代原始字符串。使用SqlCommand,从技术上讲,您正在使用参数化查询,但是您绕过了基础SQL代码的ADO.Net抽象。

因此,尽管您的代码不会阻止SQL注入,但最终的答案是sp_executesql而不是SqlCommand。

话虽这么说,我敢肯定生成使用sp_executesql的防SQL注入字符串的特殊处理要求。

请参阅:如何将值从动态SQL存储过程返回到实体框架?


-4

简单:

const string sql = "SELECT * FROM SOME_TABLE WHERE Name = @name";

并添加@name带有值的参数:

cmd.CommandText = sql;
cmd.Parameters.AddWithValue("@name", name);

36
他仍然需要从命令对象中获取实际的SQL语句以传递给API。
reustmd 2010年

他明确声明自己正在使用接受SQL字符串的API。他没有使用ADO.Net。
MHollis

@MHollis准确;这是他们需要解决的第一个问题。抱歉,没有参数就没有可行的方法。人们大喊参数是有原因的
Marc Gravell

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.