codeigniter 3不支持原生sql参数绑定,易致sql注入;应优先使用query builder(如where/update自动转义),或通过pdo预处理执行原生sql,严禁拼接用户输入。

CodeIgniter 3(CI3)本身不支持原生 SQL 中的参数绑定(如 ?1 或 :name),其 $this->db->query() 方法直接执行字符串,**若拼接用户输入,极易触发 SQL 注入**。但 CI3 提供了安全替代方案——不是靠“原生 SQL + 手动绑定”,而是通过查询构造器(Query Builder)或预处理式封装来保障安全。
用 Query Builder 替代原生 UPDATE(最推荐)
CI3 的 $this->db->where()、$this->db->update() 等方法底层自动使用 PDO 预编译占位符,输入值全程作为参数传递,不参与 SQL 解析:
- 安全写法示例:
$data = ['status' => 'active', 'updated_at' => date('Y-m-d H:i:s')];<br>$this->db->where('id', $user_id); // 自动转义 $user_id<br>$this->db->where('tenant_id', $tenant_id); // 多条件也安全<br>$this->db->update('users', $data);
- 所有
where()值、update()的数据值,均由 CI3 内部调用escape()或绑定到 PDO Statement,杜绝注入。 - 无需手动写 SQL,字段名、表名由框架控制,避免引号/括号误配问题。
必须用原生 SQL 时:自行封装 PDO 预处理
CI3 的数据库句柄($this->db->conn_id)是原生 PDO 对象,可直接调用 prepare() 和 execute():
- 安全写法示例:
$pdo = $this->db->conn_id;<br>$stmt = $pdo->prepare("UPDATE users SET status = ?, updated_at = ? WHERE id = ? AND tenant_id = ?");<br>$stmt->execute([$status, date('Y-m-d H:i:s'), $id, $tenant_id]);
- 完全绕过 CI3 查询解析器,直连 PDO 预编译机制,语义清晰、防御彻底。
- 注意:需确保
$this->db已初始化且启用 PDO(默认 MySQLi,需在database.php中配置'dbdriver' => 'pdo'并指定'subdriver')。
绝对避免的写法(高危!)
以下方式将用户变量直接拼入 SQL 字符串,属于典型注入漏洞:
$this->db->query("UPDATE users SET status = '$status' WHERE id = $id");$sql = "UPDATE users SET ... WHERE id = " . $_GET['id']; $this->db->query($sql);- 哪怕加了
mysql_real_escape_string()(已废弃)或简单htmlspecialchars(),也无法覆盖所有边界场景(如数字上下文无引号、正则绕过等)。
补充建议:最小权限 + 输入校验
即便用了参数化,也建议叠加基础防护:
- 数据库账号仅授予
UPDATE所需表的权限,禁用DROP、CREATE等高危操作。 - 对关键参数(如
$id)做类型强校验:is_numeric($id) && $id > 0,或用正则^\d+$白名单过滤。 - 日志记录异常更新行为(如批量更新、非预期字段修改),便于事后审计。











