2017-08-22 25 views
2

我需要在C#中使用字符串連接來構建SQL Server 2016腳本(該腳本將通過ADO.NET執行)。我不能使用查詢參數,我通常會這樣做,因爲腳本更像是一個設置腳本幷包含非可參數化的語句。轉義數據庫對象名稱

什麼的方式去逃避名這樣的:

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

不容易受到SQL注入?如何實現Escape?目前我在所有名稱周圍使用方括號,但是,這當然是不夠的...

+0

你可以驗證這些變量對某些檢查不要忘記[];和「etc – BugFinder

+1

@BugFinder,雖然醜陋和錯誤,可怕,並[在這裏插入更多的形容詞],這是完全合法*有一個名爲'[''在SQL Server中的表格=( – Rob

+0

真實的,但你可以使它成爲一個要求對於你的應用:)你不用:D – BugFinder

回答

2

您可以使用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