ThinkPHP 8.1 ORM 防 SQL 注入的核心是参数化查询与查询构建器的语义隔离,所有用户输入均作为绑定参数传递,表名、字段名等结构元素经白名单校验,自动类型转换与验证器前置拦截强化安全。

修复 Core bailout 状态损坏安全问题,以及 BZ2、DOM、PDO、Opcache/JIT 内存与执行错误,改进 Unicode 字素处理、URL 解析、TLS 流状态、信号分发及会话错误处理。
参数化查询是底层执行的唯一通道
ThinkPHP 8.1 所有数据库操作(包括 ORM 的 where、order、limit、save、delete 等)最终都会经过查询构建器(Query 类),而该构建器在生成 SQL 时:
• 对所有变量值(如 where('name', $input) 中的 $input)一律不拼接进 SQL 字符串;
• 而是提取为独立参数,交由 PDO 或 MySQLi 的预处理接口执行;
• 即使你写 where('score', '>', $_GET['min_score']),框架也只把 $_GET['min_score'] 当作绑定值传入,不会把它插进 "score > ?" 的字符串里再 eval 或 concat。
表名、字段名、排序方向等结构信息必须白名单校验
ORM 允许动态指定字段或条件,但对**非数据类 SQL 结构元素**有强约束:
• 表名和字段名默认来自模型定义的 $table 和 $schema,不接受任意字符串;
• 若需动态字段(如 order($field, $sort)),框架内部会调用 Builder::parseKey() 进行合法性检查——仅允许字母、数字、下划线、点号,并拒绝含空格、括号、分号、反引号的内容;
• 排序方向(ASC/DESC)被硬编码为枚举判断,if ('desc' === strtolower($sort)) { ... },而非直接拼接;
• whereRaw、queryRaw 等“绕过”接口虽存在,但明确标记为高危,且文档强调“需自行确保安全”,不属于 ORM 默认防护范畴。
自动类型转换与验证前置拦截
ORM 在执行前会对传入值做隐式归一化:
• 数字型条件(如 where('id', 123))自动转为整型,字符串型条件(如 where('status', 'active'))自动加引号包裹逻辑由驱动层完成;
• 若字段定义了类型(如 protected $type = ['id' => 'integer']),则赋值时强制类型转换,非法输入(如 '1; DROP TABLE user')会被截断或报错;
• 配合验证器(Validate)在 save() 前校验,可提前拒绝含 SQL 关键字、注释符(--、#)、分号等危险模式的输入,形成第二道防线。
不依赖转义函数,也不信任 magic_quotes
ThinkPHP 8.1 明确弃用 addslashes、mysql_real_escape_string 等传统转义手段:
• 因为转义只解决单引号闭合问题,无法防御 UNION SELECT、ORDER BY 1,2,3 等无引号上下文注入;
• 也不依赖已废弃的 magic_quotes_gpc,避免误判和兼容性陷阱;
• 全链路基于“数据与结构分离”原则,让数据库引擎本身承担语法解析职责,PHP 层只负责传递干净参数。


















