如何将表单提交的SQL WHERE子句传入Laravel 8并安全执行防SQL注入
该场景下防范SQL注入的最佳实践
1. 立即移除eval执行逻辑(最高优先级)
你当前使用的eval("return App\Models\MyModel::query()->$query")写法存在远高于SQL注入的远程代码执行风险:只要解析逻辑存在漏洞被攻击者构造特殊 payload 绕过,即可直接执行任意PHP代码,可能直接导致服务器被接管。
替代方案:修改你本地化的解析包源码,不要输出字符串形式的链式调用语句,改为返回以下任意一种可直接使用的结构,完全避免字符串执行:
- 直接返回绑定好参数的查询构造器实例
- 返回闭包,接收查询构造器作为参数后自动组装WHERE条件
- 返回独立的条件数组+参数绑定数组,手动绑定到查询构造器上
2. 多层白名单校验输入规则
- 字段白名单:预先定义允许用户查询的表字段列表,解析用户输入的WHERE子句时,校验所有出现的字段都在白名单范围内,不存在的字段直接拒绝请求,避免用户查询敏感字段或者操作不存在的字段触发异常
- 运算符白名单:除了你限定的
>、>=、<、<=、==、!=比较运算符外,还要把允许的逻辑运算符and、or/||、分组用的英文括号加入白名单,解析阶段发现不在白名单内的运算符直接拦截 - 值类型校验:根据字段类型校验对应值的格式:数值字段的值必须为合法数字,日期字段的值必须符合日期格式,字符串字段的值不允许包含特殊转义字符,不符合规则直接拦截
3. 强制使用参数绑定,禁止直接拼接SQL
修改解析逻辑时保留参数绑定能力,所有用户输入的查询值都走Laravel查询构造器的参数绑定机制,不要把用户输入的内容直接拼到SQL语句中,Laravel底层会自动对绑定参数做转义处理,从根源上避免SQL注入。
你可以在组装完查询后,调用toSql()和getBindings()方法输出SQL语句和绑定参数,校验确认没有直接拼接的用户输入内容。
4. 权限兜底降低风险
- 该场景使用的数据库账号仅开放对应表的
SELECT权限,即使出现注入漏洞,攻击者也只能查询该表的公开数据,无法删改数据或者查询其他敏感表 - 可以在查询构造器上预先追加全局查询范围,比如限定只能查询当前登录用户有权限访问的数据,即使用户构造了越权的查询条件也会被全局范围拦截
内容的提问来源于stack exchange,提问作者Mikaru
相关产品推荐
相关产品推荐

