保护 select 语句免受 sql 注入
Protect select statement from sql injection
我最近偶然发现了 api 的一部分,用户可以在其中查询特定字段:
api/models?only=id,name
是这样实现的:
@model = Model.select params[:only]
我对这一行有一种不祥的预感,我尝试了是否可以将 sql 注入到这部分代码中……并且成功了。
经过深思熟虑,我们想到了这个
@model = Model.select params[:only].split(',').map(&:to_sym)
这实际上阻止了注入。但这足以保护 API 的这一部分吗?
在这种情况下可以使用强参数吗?
query_params.require(:only).permit(:id,:name)
不起作用,因为传递的字段是字符串并且没有方法 permit
。
您可以使用ActiveRecord::Base.sanitize
Model.select Model.sanitize(params[:only])
实际上,控制器不应该使用模型的实现细节。 SQL 的 select 中的值是用逗号分隔的,而你的 API 按原样接受它们的事实是 "coincidence" 一开始不应该依赖的地方。
我将向您介绍您可能会觉得有用的工具,以便编写您的解决方案。
# Array#&, set intersection
[1, 2, 3] & [2, 4, 1] # => [1, 2]
# Model.attributes
Model.attributes #=> ['id', 'name', ...]
# You can filter down the resulting array to produce a whitelist of columns
# Splat the array into the argument list
Model.select(*params[:only].split(',') & Model::SELECT_WHITELIST)
# ...the constant above has to be defined inside the model, obviously.
我最近偶然发现了 api 的一部分,用户可以在其中查询特定字段:
api/models?only=id,name
是这样实现的:
@model = Model.select params[:only]
我对这一行有一种不祥的预感,我尝试了是否可以将 sql 注入到这部分代码中……并且成功了。
经过深思熟虑,我们想到了这个
@model = Model.select params[:only].split(',').map(&:to_sym)
这实际上阻止了注入。但这足以保护 API 的这一部分吗?
在这种情况下可以使用强参数吗?
query_params.require(:only).permit(:id,:name)
不起作用,因为传递的字段是字符串并且没有方法 permit
。
您可以使用ActiveRecord::Base.sanitize
Model.select Model.sanitize(params[:only])
实际上,控制器不应该使用模型的实现细节。 SQL 的 select 中的值是用逗号分隔的,而你的 API 按原样接受它们的事实是 "coincidence" 一开始不应该依赖的地方。
我将向您介绍您可能会觉得有用的工具,以便编写您的解决方案。
# Array#&, set intersection
[1, 2, 3] & [2, 4, 1] # => [1, 2]
# Model.attributes
Model.attributes #=> ['id', 'name', ...]
# You can filter down the resulting array to produce a whitelist of columns
# Splat the array into the argument list
Model.select(*params[:only].split(',') & Model::SELECT_WHITELIST)
# ...the constant above has to be defined inside the model, obviously.