如何生成不易受到 SQL 注入攻击的字符串
How to generate strings that are not vulnerable to SQL injection
我有一个生成查询字符串的实用程序,但是静态代码分析器(和我的同事)抱怨 "SQL Injection Attack".[=15= 的风险]
这是我的 C# 代码
public static string[] GenerateQueries(string TableName, string ColumnName)
{
return new string[] {
"SELECT * FROM " + TableName,
"SELECT * FROM " + TableName + " WHERE 1=2",
"SELECT * FROM " + TableName + " WHERE [" + TableName + "Id] = @id",
"SELECT * FROM " + TableName + " WHERE [" + TableName + "Id] = IDENT_CURRENT('" + TableName + "')",
"SELECT * FROM " + TableName + " WHERE [" + ColumnName + "] = @value"
};
}
在代码中我总是用常量字符串只调用它,例如
var queryList = GenerateQueries("Person", "Name");
有什么方法可以重写这个函数,使之成为"safe"吗?例如,如果我使用 C 而不是 C#,我可以编写一个 宏 来安全地生成字符串。
目前,我唯一的选择是 copy/paste 这块 SELECT 语句 每一个 table,很丑,而且是维护负担。
copy/paste真的是我唯一的选择吗?
编辑:
感谢您的回复,尤其是 William Leader。现在我发现我的问题是错误的。这不仅仅是我连接查询字符串的事实,而且还将它们存储在 变量 中。唯一正确的方法是使用常量构造SqlDataAdapter
,例如
var adapter = new SqlDataAdapter("SELECT * FROM PERSON");
别无选择。所以是的,会有很多 copy/paste。我开始后悔没有使用 EF。
您的代码分析器告诉您的是,您很可能应该调用带有某些参数的过程,而不是通过网络发送 SQL。
无论您是否使用宏来生成您的 SQL 语句,一点都不重要,如果您通过网络发送原始 SQL ,您可以 SQL 注入攻击
发送 SQL 命令到端点进行未经批准的呼叫。如果我们启动网络数据包嗅探器,我们可以看到您有一个配置为允许发送 SQL 命令的数据库,因此我们可以将非法 SQL 注入系统
您仍然可以依靠单个过程来调用您的更新,但如果您选择转移到过程,为什么要这样做?
EDITED to provide an example
create PROC sp_CommonSelectFromTableProc @tableName varchar(32)
AS
-- code to check the tableName parameter does not contain SQL and/or is a valid tableName
-- your procedure code here will probable use
-- exec mydynamicSQLString
-- where mydynamicSQLString is constructed using @tableName
END;
或者可能是 table 特定程序
create PROC sp_SelectFromSpecificTableProc
AS
SELECT * FROM SpecificTable
END;
需要记住的重要一点是,SQL 注入 独立于用于底层应用程序 的技术。
当应用程序包含
等构造时,它只是公开的
return new string[] {
"SELECT * FROM " + TableName,
"SELECT * FROM " + TableName + " WHERE 1=2",
"SELECT * FROM " + TableName + " WHERE [" + TableName + "Id] = @id",
"SELECT * FROM " + TableName + " WHERE [" + TableName + "Id] = IDENT_CURRENT('" + TableName + "')",
"SELECT * FROM " + TableName + " WHERE [" + ColumnName + "] = @value"
SQL注入必须在数据通道的两端进行寻址
Here 是理解如何缓解 SQL 注入攻击
的一个很好的起点
一开始我很震惊,但仔细想想,这与代码中已经有一个 SQL 语句没有什么不同,如下所示:
"SELECT * FROM Person"
我们经常做这种事。
如果
这里有一个重要的警告。只有当 如果 您可以控制函数的调用方式时,这才是正确的。因此,如果此方法是某处数据层 class 的 private 成员,那么您 可能 没问题。但我也想知道这到底有多大用处。与仅编写查询所获得的收益相比,您似乎并没有节省太多。
此外,养成忽视静态分析工具的习惯也不好。有时他们会给你一些你知道是错误的东西,但你还是会改变它,这样当他们确实发现一些重要的东西时你就不会忽视它。
我有一个生成查询字符串的实用程序,但是静态代码分析器(和我的同事)抱怨 "SQL Injection Attack".[=15= 的风险]
这是我的 C# 代码
public static string[] GenerateQueries(string TableName, string ColumnName)
{
return new string[] {
"SELECT * FROM " + TableName,
"SELECT * FROM " + TableName + " WHERE 1=2",
"SELECT * FROM " + TableName + " WHERE [" + TableName + "Id] = @id",
"SELECT * FROM " + TableName + " WHERE [" + TableName + "Id] = IDENT_CURRENT('" + TableName + "')",
"SELECT * FROM " + TableName + " WHERE [" + ColumnName + "] = @value"
};
}
在代码中我总是用常量字符串只调用它,例如
var queryList = GenerateQueries("Person", "Name");
有什么方法可以重写这个函数,使之成为"safe"吗?例如,如果我使用 C 而不是 C#,我可以编写一个 宏 来安全地生成字符串。
目前,我唯一的选择是 copy/paste 这块 SELECT 语句 每一个 table,很丑,而且是维护负担。
copy/paste真的是我唯一的选择吗?
编辑:
感谢您的回复,尤其是 William Leader。现在我发现我的问题是错误的。这不仅仅是我连接查询字符串的事实,而且还将它们存储在 变量 中。唯一正确的方法是使用常量构造SqlDataAdapter
,例如
var adapter = new SqlDataAdapter("SELECT * FROM PERSON");
别无选择。所以是的,会有很多 copy/paste。我开始后悔没有使用 EF。
您的代码分析器告诉您的是,您很可能应该调用带有某些参数的过程,而不是通过网络发送 SQL。
无论您是否使用宏来生成您的 SQL 语句,一点都不重要,如果您通过网络发送原始 SQL ,您可以 SQL 注入攻击
发送 SQL 命令到端点进行未经批准的呼叫。如果我们启动网络数据包嗅探器,我们可以看到您有一个配置为允许发送 SQL 命令的数据库,因此我们可以将非法 SQL 注入系统
您仍然可以依靠单个过程来调用您的更新,但如果您选择转移到过程,为什么要这样做?
EDITED to provide an example
create PROC sp_CommonSelectFromTableProc @tableName varchar(32)
AS
-- code to check the tableName parameter does not contain SQL and/or is a valid tableName
-- your procedure code here will probable use
-- exec mydynamicSQLString
-- where mydynamicSQLString is constructed using @tableName
END;
或者可能是 table 特定程序
create PROC sp_SelectFromSpecificTableProc
AS
SELECT * FROM SpecificTable
END;
需要记住的重要一点是,SQL 注入 独立于用于底层应用程序 的技术。
当应用程序包含
等构造时,它只是公开的return new string[] {
"SELECT * FROM " + TableName,
"SELECT * FROM " + TableName + " WHERE 1=2",
"SELECT * FROM " + TableName + " WHERE [" + TableName + "Id] = @id",
"SELECT * FROM " + TableName + " WHERE [" + TableName + "Id] = IDENT_CURRENT('" + TableName + "')",
"SELECT * FROM " + TableName + " WHERE [" + ColumnName + "] = @value"
SQL注入必须在数据通道的两端进行寻址
Here 是理解如何缓解 SQL 注入攻击
的一个很好的起点一开始我很震惊,但仔细想想,这与代码中已经有一个 SQL 语句没有什么不同,如下所示:
"SELECT * FROM Person"
我们经常做这种事。
如果
这里有一个重要的警告。只有当 如果 您可以控制函数的调用方式时,这才是正确的。因此,如果此方法是某处数据层 class 的 private 成员,那么您 可能 没问题。但我也想知道这到底有多大用处。与仅编写查询所获得的收益相比,您似乎并没有节省太多。
此外,养成忽视静态分析工具的习惯也不好。有时他们会给你一些你知道是错误的东西,但你还是会改变它,这样当他们确实发现一些重要的东西时你就不会忽视它。