防止SQL注入应优先使用预处理语句(PDO或MySQLi),辅以输入验证、禁用危险函数、最小权限数据库账户配置。

如果在PHP中执行数据库增删改查操作时直接拼接用户输入的数据,则极易导致SQL注入攻击。以下是防止SQL注入的多种安全实践方法:
一、使用预处理语句(PDO)
预处理语句将SQL逻辑与用户数据分离,数据库驱动会自动对参数进行转义和类型绑定,从根本上杜绝SQL注入可能。
1、创建PDO连接并设置错误模式为异常模式:setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION)。
2、编写带占位符的SQL语句,例如:INSERT INTO users (name, email) VALUES (?, ?)。
立即学习“PHP免费学习笔记(深入)”;
3、调用prepare()方法获取PDOStatement对象。
4、调用execute()方法传入参数数组,如['张三', 'zhang@example.com']。
5、查询操作同样适用,fetch()或fetchAll()获取结果前已确保参数安全。
二、使用预处理语句(MySQLi面向对象方式)
MySQLi也支持预处理机制,通过绑定参数实现数据与SQL结构隔离,避免字符串拼接带来的风险。
1、使用new mysqli()建立连接,并确认connect_error为null。
2、调用prepare()方法传入含问号占位符的SQL,例如:SELECT * FROM products WHERE id = ? AND status = ?。
3、使用bind_param()绑定变量,第一个参数指定类型(如"is"表示整型+字符串),后续为对应变量。
4、执行execute()后,通过get_result()获取结果集。
5、更新、删除操作同理,仅需替换SQL语句类型与绑定参数即可。
三、严格过滤与验证输入数据
在SQL执行前对用户输入进行类型校验、长度限制和内容白名单检查,可作为预处理之外的补充防御层。
1、对ID类参数使用filter_var($id, FILTER_VALIDATE_INT)验证是否为合法整数。
2、对邮箱字段使用filter_var($email, FILTER_VALIDATE_EMAIL)进行格式校验。
3、对用户名等字符串字段使用strlen()限制最大长度,并用ctype_alnum()或正则/^[a-zA-Z0-9_\x{4e00}-\x{9fa5}]+$/u限定字符范围。
4、对下拉菜单、单选按钮等可控值,采用in_array($input, $allowed_values, true)进行白名单比对。
5、拒绝处理空值、全空格、仅特殊符号等明显异常输入,直接中断后续数据库操作。
四、禁用危险函数与动态拼接
避免使用已知存在注入风险的函数组合,切断SQL注入的常见入口路径。
1、绝对禁止使用mysql_query()及其相关函数(该扩展已被PHP 7.0废弃且无预处理支持)。
2、禁止将用户输入直接嵌入SQL字符串,如"SELECT * FROM table WHERE name = '$name'"。
3、禁用eval()、create_function()、assert()等可执行动态代码的函数。
4、关闭magic_quotes_gpc(PHP 5.4+已移除),因其自动转义不可靠且干扰预处理逻辑。
5、不依赖客户端JavaScript验证,所有校验必须在服务端重复执行。
五、最小权限数据库账户配置
即使代码存在疏漏,受限的数据库账户权限也能大幅降低SQL注入成功后的危害程度。
1、为Web应用单独创建数据库用户,避免使用root或具有ALL PRIVILEGES的账号。
2、仅授予当前业务必需的权限,例如只读页面仅分配SELECT,后台管理才附加INSERT/UPDATE/DELETE。
3、禁止授予FILE、EXECUTE、PROCESS、SUPER等高危权限。
4、限制用户可访问的数据库范围,使用GRANT ... ON database_name.* TO 'user'@'host'精确指定库名。
5、生产环境数据库监听地址应绑定内网IP,禁止绑定0.0.0.0或暴露于公网。











