Ros*_*ury 9 t-sql sql-server sql-injection sql-server-2005 sql-server-2008
代码必须做些什么来清理标识符(表,视图,列),而不是用双引号将它们包装起来,并在标识符名称中出现"double up"双引号? 参考文献将不胜感激.
我继承了一个具有自定义对象关系映射(ORM)系统的代码库.SQL无法在应用程序中编写,但ORM仍必须最终生成要发送到SQL Server的SQL.所有标识符都用双引号引用.
string QuoteName(string identifier)
{
return "\"" + identifier.Replace("\"", "\"\"") + "\"";
}
Run Code Online (Sandbox Code Playgroud)
如果我在SQL中构建这个动态SQL ,我会使用内置的SQL Server QUOTENAME函数:
declare @identifier nvarchar(128);
set @identifier = N'Client"; DROP TABLE [dbo].Client; --';
declare @delimitedIdentifier nvarchar(258);
set @delimitedIdentifier = QUOTENAME(@identifier, '"');
print @delimitedIdentifier;
-- "Client""; DROP TABLE [dbo].Client; --"
Run Code Online (Sandbox Code Playgroud)
我还没有找到任何关于如何在SQL Server中转义带引号的标识符的权威文档.我找到了分隔标识符(数据库引擎),我也看到了关于清理的这个stackoverflow问题.
如果必须调用QUOTENAME函数只是为了引用那些不需要SQL Server的大量流量的标识符.
关于SQL注入,ORM似乎已经过深思熟虑了.它位于C#中,早于nHibernate端口和Entity Framework等.所有用户输入都是使用ADO.NET SqlParameter对象发送的,它只是我在这个问题中关注的标识符名称.这需要适用于SQL Server 2005和2008.
2010-03-31更新
虽然应用程序不允许在查询中允许用户输入标识符名称,但ORM通过它对ORM样式读取和自定义查询具有的查询语法来执行.正是我试图最终阻止所有可能的SQL注入攻击的ORM,因为它非常小并且易于验证而不是所有应用程序代码.
查询界面的一个简单示例:
session.Query(new TableReference("Client")
.Restrict(new FieldReference("city") == "Springfield")
.DropAllBut(new FieldReference("first_name"));
Run Code Online (Sandbox Code Playgroud)
ADO.NET发送此查询:
exec sp_executesql N'SELECT "T1"."first_name"
FROM "dbo"."Client" AS "T1"
WHERE "T1"."city" = @p1;',
N'@p1 nvarchar(30)',
N'Springfield';
Run Code Online (Sandbox Code Playgroud)
也许有必要考虑一下nHibernate查询语言(HQL)中的类似内容:
using (ISession session = NHibernateHelper.OpenSession())
{
Client client = session
.CreateCriteria(typeof(Client)) \\ <-- TableReference in example above
.Add(Restrictions.Eq("city", "Springfield")) \\ <-- FieldReference above
.UniqueResult<Client>();
return client;
}
Run Code Online (Sandbox Code Playgroud)
也许我应该看看nHibernate如何保护输入.
Mic*_*pat 20
您的QuoteName函数需要检查长度,因为T-SQL QUOTENAME函数指定它返回的最大长度.使用你的例子:
String.Format(@"declare @delimitedIdentifier nvarchar(258);
set @delimitedIdentifier = {0};", QuoteName(identifier));
Run Code Online (Sandbox Code Playgroud)
如果QuoteName(identifier)长度超过258个字符,则在分配时将以静默方式截断@delimitedIdentifier.当这种情况发生时,你就有可能@delimitedIdentifier不正当地逃脱.
有一个MSDN文章由巴拉Neerumalla,一个"微软安全软件开发商",解释更深入的话题.本文还包含了我发现的"关于如何在SQL Server中转义引用标识符的权威文档"中最接近的内容:
转义机制只是将右方括号的出现加倍.您不需要对其他字符执行任何操作,包括左方括号.
这是我目前使用的C#代码:
/// <summary>
/// Returns a string with the delimiters added to make the input string
/// a valid SQL Server delimited identifier. Brackets are used as the
/// delimiter. Unlike the T-SQL version, an ArgumentException is thrown
/// instead of returning a null for invalid arguments.
/// </summary>
/// <param name="name">sysname, limited to 128 characters.</param>
/// <returns>An escaped identifier, no longer than 258 characters.</returns>
public static string QuoteName(string name) { return QuoteName(name, '['); }
/// <summary>
/// Returns a string with the delimiters added to make the input string
/// a valid SQL Server delimited identifier. Unlike the T-SQL version,
/// an ArgumentException is thrown instead of returning a null for
/// invalid arguments.
/// </summary>
/// <param name="name">sysname, limited to 128 characters.</param>
/// <param name="quoteCharacter">Can be a single quotation mark ( ' ), a
/// left or right bracket ( [] ), or a double quotation mark ( " ).</param>
/// <returns>An escaped identifier, no longer than 258 characters.</returns>
public static string QuoteName(string name, char quoteCharacter) {
name = name ?? String.Empty;
const int sysnameLength = 128;
if (name.Length > sysnameLength) {
throw new ArgumentException(String.Format(
"name is longer than {0} characters", sysnameLength));
}
switch (quoteCharacter) {
case '\'':
return String.Format("'{0}'", name.Replace("'", "''"));
case '"':
return String.Format("\"{0}\"", name.Replace("\"", "\"\""));
case '[':
case ']':
return String.Format("[{0}]", name.Replace("]", "]]"));
default:
throw new ArgumentException(
"quoteCharacter must be one of: ', \", [, or ]");
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
8387 次 |
| 最近记录: |