除了将标识符(表、视图、列)用双引号括起来以及标识符名称中存在的“双引号”之外,代码还必须执行其他操作吗?参考文献将不胜感激。
我继承了一个具有自定义对象关系映射 (ORM) 系统的代码库。 SQL 无法在应用程序中编写,但 ORM 最终仍必须生成 SQL 并将其发送到 SQL Server。所有标识符都用双引号引起来。
string QuoteName(string identifier)
{
return "\"" + identifier.Replace("\"", "\"\"") + "\"";
}
如果我正在构建这个动态 SQLin 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; --"
我还没有找到任何关于如何在 SQL Server 中转义带引号的标识符的明确文档。我已经发现分隔标识符(数据库引擎)我还看到了这个计算器问题关于消毒。
如果必须调用 QUOTENAME 函数只是为了引用标识符,那么 SQL Server 的流量就很大,这是不必要的。
ORM 似乎在 SQL 注入方面经过了深思熟虑。它是用 C# 编写的,早于 nHibernate 端口和实体框架等。所有用户输入都是使用 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"));
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';
也许思考一下 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;
}
也许我应该看看 nHibernate 如何保护输入。