当它作为字符串出现时,保护完整的 where 语句
Secure full where statement when it comes as a string
我有以下 C# 函数
SomeFunction(string table, string column, string where) {
Sql sql = new Sql("SELECT ");
// [...] validate table and column values
sql.Append(column);
sql.Append(" FROM ");
sql.Append(table);
sql.Append(" WHERE ");
sql.Append(where); // This is the issue
}
如您所见,这太糟糕了,我正在处理这个非常古老的遗留代码并更改函数签名和客户使用它的方式是不可行的。我要做的是保护 'where' 子句。此子句可能包含任意数量的条件和数据类型。
我有很多想法,但我不认为它们是一个好的解决方案,我认为这需要正确编写和测试的代码,但如果我自己突然这样做,它可能会有漏洞.以下是一些想法:
- 按 char '=' 拆分字符串 -> 如果那不是条件运算符怎么办
- 查找字符串是否包含分号 -> SELECT 子句仍然存在漏洞,并且可能其中一个条件包含该字符,因此它会给出误报
如果您有任何 idea/suggestion/pointing 正确的方向,我将不胜感激。
如果 where
子句目前是基于预先编写的 string
,那么坦率地说,我认为尝试 "secure" 它不是一种可行的方法。这在理论上是可能的,但如果组合和妥协(注入)where
子句是合法的(但滥用),则任何解析 SQL 的尝试都将失败。那时:您已经忘记了最初的意图。这就是 SQL 注入的全部要点:结果 SQL 是有效的 SQL - 所以你很难分辨两者之间的区别where Name = 'Fred Orson' -- check name
(可能没问题)和 where Name = 'Fred' Or 1=1 --'
(注入 - 查询扩大)。
所以:虽然我承认你说:
changing the function signature and the way the clients use it is just not feasible.
不是 更改函数签名并不能真正帮助您解决问题。试图检测某些模式只是一场军备竞赛,你需要每次都赢,而攻击者只需要赢一次。
如果是我,我会做这样的事情:
[Obsolete("Please specify parameters separately - use 'null' if no parameters are needed")]
SomeFunction(string table, string column, string where) {
return SomeFunction(table, column, where, null);
}
SomeFunction(string table, string column, string where, object args) {
// ...
}
并使用类似 "Dapper" 的方法来组合来自 args
参数的参数 - 或者仅将 "Dapper" 本身用于 运行 查询,并使用它免费功能。
这种方法:
- 防止添加危险 API 的新用途
- 让现有代码暂时继续工作
- 但可以让您通过查看警告来跟踪有多少未解决的问题调用
编辑:注意:args
参数的点是为了让调用者参数化他们的输入,即
string name = ...
var users = SomeFunction("Users", "Id", "Name=@name", new { name });
使用 SomeFunction
分解 args
并从 args
上的属性添加参数 name/value 对(如果它是非空的)。组成参数集的方法有多种,但此处显示的方法简单且易于正确实施 - 这对我来说是一个明显的胜利。
我有以下 C# 函数
SomeFunction(string table, string column, string where) {
Sql sql = new Sql("SELECT ");
// [...] validate table and column values
sql.Append(column);
sql.Append(" FROM ");
sql.Append(table);
sql.Append(" WHERE ");
sql.Append(where); // This is the issue
}
如您所见,这太糟糕了,我正在处理这个非常古老的遗留代码并更改函数签名和客户使用它的方式是不可行的。我要做的是保护 'where' 子句。此子句可能包含任意数量的条件和数据类型。
我有很多想法,但我不认为它们是一个好的解决方案,我认为这需要正确编写和测试的代码,但如果我自己突然这样做,它可能会有漏洞.以下是一些想法:
- 按 char '=' 拆分字符串 -> 如果那不是条件运算符怎么办
- 查找字符串是否包含分号 -> SELECT 子句仍然存在漏洞,并且可能其中一个条件包含该字符,因此它会给出误报
如果您有任何 idea/suggestion/pointing 正确的方向,我将不胜感激。
如果 where
子句目前是基于预先编写的 string
,那么坦率地说,我认为尝试 "secure" 它不是一种可行的方法。这在理论上是可能的,但如果组合和妥协(注入)where
子句是合法的(但滥用),则任何解析 SQL 的尝试都将失败。那时:您已经忘记了最初的意图。这就是 SQL 注入的全部要点:结果 SQL 是有效的 SQL - 所以你很难分辨两者之间的区别where Name = 'Fred Orson' -- check name
(可能没问题)和 where Name = 'Fred' Or 1=1 --'
(注入 - 查询扩大)。
所以:虽然我承认你说:
changing the function signature and the way the clients use it is just not feasible.
不是 更改函数签名并不能真正帮助您解决问题。试图检测某些模式只是一场军备竞赛,你需要每次都赢,而攻击者只需要赢一次。
如果是我,我会做这样的事情:
[Obsolete("Please specify parameters separately - use 'null' if no parameters are needed")]
SomeFunction(string table, string column, string where) {
return SomeFunction(table, column, where, null);
}
SomeFunction(string table, string column, string where, object args) {
// ...
}
并使用类似 "Dapper" 的方法来组合来自 args
参数的参数 - 或者仅将 "Dapper" 本身用于 运行 查询,并使用它免费功能。
这种方法:
- 防止添加危险 API 的新用途
- 让现有代码暂时继续工作
- 但可以让您通过查看警告来跟踪有多少未解决的问题调用
编辑:注意:args
参数的点是为了让调用者参数化他们的输入,即
string name = ...
var users = SomeFunction("Users", "Id", "Name=@name", new { name });
使用 SomeFunction
分解 args
并从 args
上的属性添加参数 name/value 对(如果它是非空的)。组成参数集的方法有多种,但此处显示的方法简单且易于正确实施 - 这对我来说是一个明显的胜利。