强参数不防SQL注入,仅过滤控制器参数;SQL注入防护依赖ActiveRecord参数化查询,若强参数未配置白名单导致手动拼接SQL,则引发注入风险。

强参数(Strong Parameters)本身不防 SQL 注入,它只管控制器层的参数过滤;SQL 注入防护靠的是 ActiveRecord 的参数化查询机制——但强参数没配对,会间接导致你被迫写危险查询。
为什么强参数和 SQL 注入不是一回事
强参数的作用是拒绝未声明的参数进入 params,比如禁止攻击者传 admin=true 进来提权。但它不会转义字符串、不会阻止 "name = '#{params[:name]}'" 这种拼接。一旦你因参数没被允许而 fallback 到手动拼 SQL,注入就发生了。
常见错误现象:params[:sort] 没进白名单 → 你在 controller 里写 User.order("#{params[:sort]}") → 日志里看到 ORDER BY email; DROP TABLE users; --
- 强参数不处理
order、group、select这类动态 SQL 子句的字段名 - 它也不校验
params[:conditions]这种自定义条件字符串 - 它的输出仍是 Ruby 对象,不是 SQL 字符串,所以不参与查询构建环节
哪些地方必须配合强参数才能安全用 ActiveRecord
当你要把用户输入塞进 where、find_by、update 等方法时,强参数是第一道闸门:它确保你拿到的是干净、结构明确的值,而不是一堆混杂字段让你不敢直接传给查询接口。
例如:
def user_params params.require(:user).permit(:email, :name, :status) end
这样你才能放心写:
User.where(user_params)
而不是被迫拼字符串:
"WHERE email = '#{params[:user][:email]}' AND name = '#{params[:user][:name]}'"- 哈希式
where(如User.where(email: params[:email]))依赖键名可控 —— 强参数确保params[:email]是你允许的字段 - 如果没做
permit,params[:email]可能根本不存在,或被嵌套在未授权结构里,逼你用params.to_unsafe_h或手动取值 - Ransack 搜索也依赖强参数:比如
search_params = params.permit(:q => [:name_eq, :email_cont]),否则q[password_eq]可能绕过校验
order 和 sort 类动态字段怎么用强参数兜底
强参数不能直接 permit 字段名,但可以配合白名单逻辑做守门人。重点不是“让强参数放行 sort”,而是用它把原始输入先收进来,再由你校验。
正确做法:
def index @users = User.all @users = @users.order(sort_column + " " + sort_direction) end <p>private</p><p>def sort_column</p><h1>先让强参数收下原始值</h1><p>column = params.permit(:sort)[:sort]</p><h1>再白名单校验</h1><p>%w[name email created_at].include?(column) ? column : "name" end</p><p>def sort_direction dir = params.permit(:direction)[:direction] %w[asc desc].include?(dir) ? dir : "asc" end
- 别写
params.require(:sort).permit(:column, :direction)——:sort不是嵌套结构,permit对单层键无效 - 用
params.permit(:sort, :direction)是安全的,它只是防止多余参数污染,不负责内容合法性 - Active Record 的
order方法不接受参数化占位符,所以字段名校验这步绕不开,强参数只是帮你把输入“拿稳”,不丢、不乱、不嵌套
Ransack 场景下强参数的典型误用
Ransack 的搜索条件(如 q[name_cont])本质是嵌套哈希,强参数配置稍有偏差就会放行非法谓词或字段。
危险写法:
params.permit(q: [:name_cont, :email_eq])
问题:只允许了固定谓词,但攻击者可传 q[password_eq](如果 password 是数据库字段),或更糟的 q[admin_or_1_eq](触发 Ransack 的 OR 构造)。
推荐写法:
def search_params
params.require(:q).permit(
:name_cont,
:email_cont,
:status_eq,
# 白名单限定字段+谓词组合
name_or_email_cont: []
)
end- Ransack 默认开启
sanitize_scope_args,但只处理布尔/数值类型转换,不防字段名注入 - 像
name_or_email_cont这种复合谓词,必须显式permit,否则 Ransack 会静默忽略或 fallback 到不安全行为 - 永远不要
permit!或to_h后直接喂给 Ransack,那等于放弃所有边界
真正容易被忽略的点:强参数配得再严,只要 controller 里出现任何 "#{}"、find_by_sql、connection.execute,前面所有配置都归零。防御的核心不是“怎么配强参数”,而是“有没有哪一行代码绕过了 ActiveRecord 的参数绑定”。

















