php如何防止sql注入|优先参数化绑定再叠加表单过滤
之前做企业后台登录模块开发时,真切踩过SQL注入的雷,也彻底摸透了php如何防止sql注入的落地操作,所有能用的方法都是实打实测试验证过的,没有半点空泛的理论。
最开始写代码图省事,直接把前端POST获取的用户名和密码变量,拼接进SQL查询语句里。当时觉得内部后台权限严格,不会有人恶意测试,完全没做任何过滤和处理。上线试运行第三天,测试人员随便输入了一段恶意字符,直接绕过了登录验证,不用正确账号密码就成功登录了后台系统。
那段出问题的代码特别典型,就是新手最容易犯的错误,直接将用户输入拼接到SQL语句。接收前端的`$username`和`$pwd`参数后,直接写`select * from admin where username='$username' and password='$pwd'`。只要输入`admin' or 1=1 #`,整条SQL语句的判断条件就会被强制恒成立,数据库会直接返回所有管理员数据,登录校验彻底失效。
发现漏洞的第一时间,只做了简单的字符替换处理,用函数过滤掉单引号、井号、or这些常见的注入关键字。本以为这样就能解决问题,结果没过半天,又被测出新的漏洞。有人用大小写混合的关键字、换行分隔的恶意字符,轻松绕过了简单的字符过滤,注入攻击依旧可以成功执行。
那一刻突然反应过来,靠黑名单过滤恶意字符根本治标不治本,攻击者的变形方式无穷无尽,永远堵不完所有违规字符。单纯拦截关键字和特殊符号,只会不断被绕过,根本没法从根源杜绝SQL注入风险。
后来彻底推翻了之前的写法,改用PDO预处理语句搭配参数化绑定,这是所有防护手段里最核心、最有效的一步。不再直接拼接变量到SQL语句,而是先写固定的SQL模板,用占位符替代用户输入,再通过参数绑定的方式传入数据。
数据库会先编译固定的SQL模板,生成执行逻辑,后续传入的用户输入只会被单纯识别为普通字符串,无论包含什么恶意字符,都不会被解析成SQL执行语句,从根源切断注入通道。改完之后反复测试各类注入 payload,不管是万能密码、字符闭合注入,还是嵌套恶意语句,全部失效,登录接口的注入漏洞彻底修复。
做完核心防护后,又补了两层辅助防护,适配日常开发的各种场景。首先是强制开启PHP的魔术引号过滤,对所有GET、POST、COOKIE提交的参数自动转义特殊字符,杜绝基础的字符闭合注入。其次做了数据库账号权限限制,项目连接数据库的账号,只授予查询、新增、修改的基础权限,彻底禁用删除、修改数据表结构的高危权限。
就算极端情况下出现注入漏洞,攻击者也没法篡改、删除数据库核心数据,把风险降到最低。
很多人会忽略输入格式校验这个细节,开发时只要涉及账号、手机号、ID这类固定格式的参数,全部提前做正则校验。比如用户名只允许字母、数字和下划线,ID强制限制为纯数字,不符合格式的输入直接拦截,不传入数据库,减少被攻击的概率。
项目迭代后期,删掉了所有自定义的字符过滤函数,只保留参数化绑定、权限限制、格式校验这三套组合方式。多余的过滤逻辑只会增加代码冗余,还容易出现校验冲突,核心防护到位后,简单的辅助手段就足够支撑系统安全运行。
目前所有PHP项目的数据库操作,全部统一使用参数化预处理的写法,每次写完接口都会手动输入各类恶意字符测试注入漏洞,确保每一个对外接口都不存在安全隐患。