SQL 注入动态构建的机会 SQL
Chances of SQL injection in dynamically constructed SQL
我在 MySQL
中有这样的查询
val selectQ = "SELECT NAME FROM EMPLOYEE"
val date = "2010-10-10"
val age = 10
现在我有一些动态的 AND 子句,
喜欢
val whereNameFilter = "WHERE date = $date"
val andAgeFilter = "AND age = $age"
我根据条件连接 whereNameFilter
和 andAgeFilter
因为有时我根本不需要连接它
我不想使用 ORM,因为 ORM 已被证明性能低下,我想在 Plain SQL 中实现,因为它已被证明具有高性能。同样,我有一些基于输入字段的动态子查询。
假设我的所有输入都经过清理并抛出相关错误,在查询构造之前,SQL 注入的机会是多少?
如果有机会,有什么方法可以预防?是否有任何实用程序可以帮助我使用动态 AND / OR / IN 和动态子查询动态构建查询?
我的编程语言是 Scala
您通过在应用程序中对它们进行硬编码来控制的字符串与来自不受信任来源的字符串之间存在差异。
我不是 Scala 程序员,所以我会这样形成伪代码:
conditions = Array()
params = Array()
selectQ = "SELECT NAME FROM EMPLOYEE WHERE true
if (date_input) {
selectQ += "AND date = ?"
params.append(date_input)
}
if (age_input) {
selectQ += "AND age = ?"
params.append(age_input)
}
query = prepare(selectQ)
fore (params as i=>p) {
query.setString(i, p)
}
此技术确保只有您硬编码的字符串才会附加到您的 SQL 查询。
其他内容合并为绑定参数。查询参数 NOT 只是附加到查询,它们保持分开,直到查询的 prepare()
之后。之后,查询语法已经被SQL引擎解析,所以任何内容都不会影响解析。
回复您的评论:
如果表达式本身是不可信内容的一部分(包括但不限于用户输入),那么将它们逐字插入到您的 SQL 查询中当然是 SQL 注入。你不能这样做。
您可以将表达式列入白名单。也就是说,将它们与已知接受的表达式列表进行比较,如果它们不在该列表中,则拒绝它们。
更好的方法是允许客户端 select 某个标识符的已知安全表达式。例如,客户端将传递一个整数 7,这将对应于应用程序中硬编码的 "AND age = ?"。
如果你真的不能限制被接受的表达的多样性,并且你不能将它们列入白名单,那么是的,那是 SQL 设计注入。 这永远不会是一个安全的应用程序。在我看来,您不应该实现执行此操作的代码。
这就像您是电工而不是软件工程师,而您的雇主告诉您 运行 一些未绝缘的电线穿过一桶油性抹布。我认为拒绝服从他们的命令是你的职业责任。他们可能会解雇你并找其他人来做,但至少你不会为不可避免的房屋火灾负责。
我在 MySQL
中有这样的查询val selectQ = "SELECT NAME FROM EMPLOYEE"
val date = "2010-10-10"
val age = 10
现在我有一些动态的 AND 子句, 喜欢
val whereNameFilter = "WHERE date = $date"
val andAgeFilter = "AND age = $age"
我根据条件连接 whereNameFilter
和 andAgeFilter
因为有时我根本不需要连接它
我不想使用 ORM,因为 ORM 已被证明性能低下,我想在 Plain SQL 中实现,因为它已被证明具有高性能。同样,我有一些基于输入字段的动态子查询。 假设我的所有输入都经过清理并抛出相关错误,在查询构造之前,SQL 注入的机会是多少?
如果有机会,有什么方法可以预防?是否有任何实用程序可以帮助我使用动态 AND / OR / IN 和动态子查询动态构建查询?
我的编程语言是 Scala
您通过在应用程序中对它们进行硬编码来控制的字符串与来自不受信任来源的字符串之间存在差异。
我不是 Scala 程序员,所以我会这样形成伪代码:
conditions = Array()
params = Array()
selectQ = "SELECT NAME FROM EMPLOYEE WHERE true
if (date_input) {
selectQ += "AND date = ?"
params.append(date_input)
}
if (age_input) {
selectQ += "AND age = ?"
params.append(age_input)
}
query = prepare(selectQ)
fore (params as i=>p) {
query.setString(i, p)
}
此技术确保只有您硬编码的字符串才会附加到您的 SQL 查询。
其他内容合并为绑定参数。查询参数 NOT 只是附加到查询,它们保持分开,直到查询的 prepare()
之后。之后,查询语法已经被SQL引擎解析,所以任何内容都不会影响解析。
回复您的评论:
如果表达式本身是不可信内容的一部分(包括但不限于用户输入),那么将它们逐字插入到您的 SQL 查询中当然是 SQL 注入。你不能这样做。
您可以将表达式列入白名单。也就是说,将它们与已知接受的表达式列表进行比较,如果它们不在该列表中,则拒绝它们。
更好的方法是允许客户端 select 某个标识符的已知安全表达式。例如,客户端将传递一个整数 7,这将对应于应用程序中硬编码的 "AND age = ?"。
如果你真的不能限制被接受的表达的多样性,并且你不能将它们列入白名单,那么是的,那是 SQL 设计注入。 这永远不会是一个安全的应用程序。在我看来,您不应该实现执行此操作的代码。
这就像您是电工而不是软件工程师,而您的雇主告诉您 运行 一些未绝缘的电线穿过一桶油性抹布。我认为拒绝服从他们的命令是你的职业责任。他们可能会解雇你并找其他人来做,但至少你不会为不可避免的房屋火灾负责。