Rails sql 注入的刹车警告
Rails brakeman warning of sql injection
我的模型中有一个范围:
scope :assigned_to_user, ->(user) {
task_table = UserTask.table_name
joins("INNER JOIN #{task_table}
ON #{task_table}.user_id = #{user.id}
AND (#{task_table}.type_id = #{table_name}.type_id)
AND (#{task_table}.manager_id = #{table_name}.manager_id)
")
}
所以在运行 brakeman report 后我收到这个警告:
assigned_to_user | SQL Injection | Possible
所以我尝试了以下方法:
scope :assigned_to_user, ->(user) {
task_table = UserTask.table_name
joins(ActiveRecord::Base::sanitize("INNER JOIN #{task_table}
ON #{task_table}.user_id = #{user.id}
AND (#{task_table}.type_id = #{table_name}.type_id)
AND (#{task_table}.manager_id = #{table_name}.manager_id)
"))
}
这对我不起作用,因为它在 sql 的前后添加了 '
(撇号)。因此,当我将其用作 returns 一些结果的查询的一部分并且我应用此范围时,它会生成不正确的 sql.
我也试过这个:
scope :assigned_to_user, ->(user) {
task_table = UserTask.table_name
joins("INNER JOIN #{task_table}
ON #{task_table}.user_id = ?
AND (#{task_table}.type_id = #{table_name}.type_id)
AND (#{task_table}.manager_id = #{table_name}.manager_id)
", user.id)
}
甚至不构建语句。并尝试了其他一些没有用甚至不值得一提的东西。有人知道如何解决这个问题吗?
经过某种研究后,我会使用这里。
有一个名为 sanitize_sql_array
(ref) 的方法,您可以通过向其传递 sql 字符串和替换值来使用它来转义语句,例如:
sanitize_sql_array(['user_id = :user_id', user_id: 5])
# => "user_id = 5"
如果我们将 table 名称传递给此方法,它也会对其进行转义,但会在值上应用 ActiveRecord::Base.connection
对象的 quote
方法,该值用于转义变量,但不转义 table 名称。也许有时它会起作用,但当我使用 PostrgreSQL 时它对我来说失败了,因为 quote
方法使用单引号,但 PostgreSQL 需要对 table 名称使用双引号。
sanitize_sql_array([
'INNER JOIN :table_name ON :table_name.user_id = :user_id',
{ table_name: 'users', user_id: 5 }
])
# => "INNER JOIN 'users' ON 'users'.user_id = 5"
connection
对象也有一个方法 quote_table_name
,可以单独应用于 table 名称,以确保它们被转义 + 使用 sanitize_sql_array
为用户id.
scope :assigned_to_user, -> (user) {
task_table = connection.quote_table_name(UserTask.table_name)
current_table = connection.quote_table_name(table_name)
sanitized_sql = sanitize_sql_array([
"INNER JOIN #{task_table}
ON #{task_table}.user_id = :user_id
AND (#{task_table}.type_id = #{current_table}.type_id)
AND (#{task_table}.manager_id = #{current_table}.manager_id)",
{ user_id: user.id }
])
joins(sanitized_sql)
}
或者您实际上可以在 user.id
上使用 sanitize
而不是将所有内容包装在 sanitize_sql_array
方法调用 (#{sanitize(user.id)}
).
中
顺便说一句,Brakeman 不会显示任何警告,因为查询已移至变量。 Brakeman 从字面上按原样解析您的代码,它不知道变量及其内容。所以这一切只是为了让你自己确定一切都被转义了。
为了让 Brakeman 闭嘴,您可以将查询移动到变量:
scope :assigned_to_user, -> (user) {
task_table = UserTask.table_name
query = "INNER JOIN #{task_table}
ON #{task_table}.user_id = #{user.id}
AND (#{task_table}.type_id = #{table_name}.type_id)
AND (#{task_table}.manager_id = #{table_name}.manager_id)"
joins(query)
}
我的模型中有一个范围:
scope :assigned_to_user, ->(user) {
task_table = UserTask.table_name
joins("INNER JOIN #{task_table}
ON #{task_table}.user_id = #{user.id}
AND (#{task_table}.type_id = #{table_name}.type_id)
AND (#{task_table}.manager_id = #{table_name}.manager_id)
")
}
所以在运行 brakeman report 后我收到这个警告:
assigned_to_user | SQL Injection | Possible
所以我尝试了以下方法:
scope :assigned_to_user, ->(user) {
task_table = UserTask.table_name
joins(ActiveRecord::Base::sanitize("INNER JOIN #{task_table}
ON #{task_table}.user_id = #{user.id}
AND (#{task_table}.type_id = #{table_name}.type_id)
AND (#{task_table}.manager_id = #{table_name}.manager_id)
"))
}
这对我不起作用,因为它在 sql 的前后添加了 '
(撇号)。因此,当我将其用作 returns 一些结果的查询的一部分并且我应用此范围时,它会生成不正确的 sql.
我也试过这个:
scope :assigned_to_user, ->(user) {
task_table = UserTask.table_name
joins("INNER JOIN #{task_table}
ON #{task_table}.user_id = ?
AND (#{task_table}.type_id = #{table_name}.type_id)
AND (#{task_table}.manager_id = #{table_name}.manager_id)
", user.id)
}
甚至不构建语句。并尝试了其他一些没有用甚至不值得一提的东西。有人知道如何解决这个问题吗?
经过某种研究后,我会使用这里。
有一个名为 sanitize_sql_array
(ref) 的方法,您可以通过向其传递 sql 字符串和替换值来使用它来转义语句,例如:
sanitize_sql_array(['user_id = :user_id', user_id: 5])
# => "user_id = 5"
如果我们将 table 名称传递给此方法,它也会对其进行转义,但会在值上应用 ActiveRecord::Base.connection
对象的 quote
方法,该值用于转义变量,但不转义 table 名称。也许有时它会起作用,但当我使用 PostrgreSQL 时它对我来说失败了,因为 quote
方法使用单引号,但 PostgreSQL 需要对 table 名称使用双引号。
sanitize_sql_array([
'INNER JOIN :table_name ON :table_name.user_id = :user_id',
{ table_name: 'users', user_id: 5 }
])
# => "INNER JOIN 'users' ON 'users'.user_id = 5"
connection
对象也有一个方法 quote_table_name
,可以单独应用于 table 名称,以确保它们被转义 + 使用 sanitize_sql_array
为用户id.
scope :assigned_to_user, -> (user) {
task_table = connection.quote_table_name(UserTask.table_name)
current_table = connection.quote_table_name(table_name)
sanitized_sql = sanitize_sql_array([
"INNER JOIN #{task_table}
ON #{task_table}.user_id = :user_id
AND (#{task_table}.type_id = #{current_table}.type_id)
AND (#{task_table}.manager_id = #{current_table}.manager_id)",
{ user_id: user.id }
])
joins(sanitized_sql)
}
或者您实际上可以在 user.id
上使用 sanitize
而不是将所有内容包装在 sanitize_sql_array
方法调用 (#{sanitize(user.id)}
).
顺便说一句,Brakeman 不会显示任何警告,因为查询已移至变量。 Brakeman 从字面上按原样解析您的代码,它不知道变量及其内容。所以这一切只是为了让你自己确定一切都被转义了。
为了让 Brakeman 闭嘴,您可以将查询移动到变量:
scope :assigned_to_user, -> (user) {
task_table = UserTask.table_name
query = "INNER JOIN #{task_table}
ON #{task_table}.user_id = #{user.id}
AND (#{task_table}.type_id = #{table_name}.type_id)
AND (#{task_table}.manager_id = #{table_name}.manager_id)"
joins(query)
}