转义数据库对象名称
Escape database object names
我需要使用 C# 中的字符串连接构建一个 SQL Server 2016 脚本(该脚本将通过 ADO.NET 执行)。我不能使用我通常会使用的查询参数,因为该脚本更像是一个设置脚本并且包含不可参数化的语句。
转义名称的方法是什么:
"ALTER DATABASE " + Escape(databaseName) + " ADD ..."
不易受到 SQL 注入?如何实现Escape
?目前我在所有名称周围都使用方括号,但是,这当然不够...
您可以使用 QUOTENAME SQL 服务器内置函数来实现此目的。
因为它看起来很像您正在用 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 命名空间中的 classes 来展示这一点,这里有一个 class 执行此行为,当给定一个连接字符串用于交谈时至 SQL 服务器:
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?
如果您使用的是常规 .NET,请使用 SqlCommandBuilder.QuoteIdentifier:
Given an unquoted identifier in the correct catalog case, returns the correct quoted form of that identifier. This includes correctly escaping any embedded quotes in the identifier.
https://docs.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlcommandbuilder.quoteidentifier
我需要使用 C# 中的字符串连接构建一个 SQL Server 2016 脚本(该脚本将通过 ADO.NET 执行)。我不能使用我通常会使用的查询参数,因为该脚本更像是一个设置脚本并且包含不可参数化的语句。
转义名称的方法是什么:
"ALTER DATABASE " + Escape(databaseName) + " ADD ..."
不易受到 SQL 注入?如何实现Escape
?目前我在所有名称周围都使用方括号,但是,这当然不够...
您可以使用 QUOTENAME SQL 服务器内置函数来实现此目的。
因为它看起来很像您正在用 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 命名空间中的 classes 来展示这一点,这里有一个 class 执行此行为,当给定一个连接字符串用于交谈时至 SQL 服务器:
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?
如果您使用的是常规 .NET,请使用 SqlCommandBuilder.QuoteIdentifier:
Given an unquoted identifier in the correct catalog case, returns the correct quoted form of that identifier. This includes correctly escaping any embedded quotes in the identifier.
https://docs.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlcommandbuilder.quoteidentifier