转义数据库对象名称

转义数据库对象名称

问题描述:

我需要在C#中使用字符串连接来构建SQL Server 2016脚本(该脚本将通过ADO.NET执行)。我不能使用查询参数,我通常会这样做,因为脚本更像是一个设置脚本并包含非可参数化的语句。转义数据库对象名称

什么的方式去逃避名这样的:

"ALTER DATABASE " + Escape(databaseName) + " ADD ..." 

不容易受到SQL注入?如何实现Escape?目前我在所有名称周围使用方括号,但是,这当然是不够的...

+0

你可以验证这些变量对某些检查不要忘记[];和“etc – BugFinder

+1

@BugFinder,虽然丑陋和错误,可怕,并[在这里插入更多的形容词],这是完全合法*有一个名为'[''在SQL Server中的表格=( – Rob

+0

真实的,但你可以使它成为一个要求对于你的应用:)你不用:D – BugFinder

您可以使用SQL Server内置函数QUOTENAME来实现此目的。

因为它看起来非常像在C#中构建脚本,所以在使用SQL执行它之前,您可能希望拥有一个C#函数,它可以访问数据库以执行此操作,也许还将结果值存储在Dictionary<string, string>中以消除已经引用的字符串的往返行程。

例如:

private Dictionary<string, string> _quotedNames = new Dictionary<string, string>(); 

private string GetSqlQuotedName(string name) 
{ 
    if (!_quotedNames.ContainsKey(name)) 
    { 
     _quotedNames[name] = GetSqlQuotedNameFromSqlServer(name); 
    } 

    return _quotedNames[name]; 
} 

private string GetSqlQuotedNameFromSqlServer(string name) 
{ 
    /// Code here to use your Data access method of choice to basically execute 
    /// SELECT QUOTENAME(name) and return it 
} 

其实,只是为了显示这个在System.Data.SqlClient命名空间中的类,下面是执行这种行为,给使用通话连接字符串当一个类到SQL Server:

public class SqlNameEscaper 
{ 
    private Dictionary<string, string> _quotedNames = new Dictionary<string, string>(); 
    private string _connectionString = string.Empty; 

    public SqlNameEscaper(string connectionString) 
    { 
     _connectionString = connectionString; 
    } 

    public string GetSqlQuotedName(string name) 
    { 
     if (!_quotedNames.ContainsKey(name)) 
     { 
      _quotedNames[name] = GetSqlQuotedNameFromSqlServer(name); 
     } 

     return _quotedNames[name]; 
    } 

    private string GetSqlQuotedNameFromSqlServer(string name) 
    { 
     using (var connection = new SqlConnection(_connectionString)) 
     { 
      connection.Open(); 
      using (var command = new SqlCommand("SELECT QUOTENAME(@name)", connection)) 
      { 
       command.Parameters.AddWithValue("@name", name); 
       var result = command.ExecuteScalar(); 

       return result.ToString(); 
      } 
     } 
    } 
} 

这然后可以通过做这个被称为:

var sne = new SqlNameEscaper(@"CONNECTION_STRING_HERE"); 
var bracket = sne.GetSqlQuotedName("["); 

或者,在你的榜样的背景:

var sqlNameEscaper = new SqlNameEscaper(@"CONNECTION_STRING_HERE"); 
var text = "ALTER DATABASE " + sqlNameEscaper.GetSqlQuotedName(databaseName) + " ADD ..."; 

还有上dba.stackexchange.com这是值得拥有的关于这个主题的读取问题:Should we still be using QUOTENAME to protect from injection attacks?

+0

是QUOTENAME也可用于“参数”,如'ADD FILE(name ='',...)'? –

+0

@DR - 可能,尽管您更有可能开始达到128个字符的限制,即d任何提及。如果你使用我上面提出的包装函数,那么结果字符串可以用在你想要的任何地方! =) – Rob