预编译能否 100%防 sql 注入?

ops/2025/3/30 21:55:42/

🌟 什么是 SQL 注入?

SQL 注入(SQL Injection)是指攻击者利用特殊输入,让数据库执行它本来不应该执行的代码,从而获取或篡改数据。

就像在考试的时候偷偷改题目,让老师改成你想要的内容! 😱


🌟 先来看一个正常的 SQL 查询

假设你的网站有一个登录功能,代码是这样的:

🔹 登录代码

$username = $_GET['username'];  
$password = $_GET['password'];  

$query = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";

✅ 这个代码的意思是:
👉 从 users 表里查找 用户名 = $username密码 = $password 的用户。

如果数据库里有这条数据,用户就可以登录!

🌟 用户输入正常数据(正确方式)

假设用户输入:

username = admin
password = 123456

最终SQL语句:

SELECT * FROM users WHERE username = 'admin' AND password = '123456';

✅ 如果 admin 这个用户的密码是 123456,那么数据库会返回这个用户的信息,表示登录成功!

🚨 但如果攻击者输入特殊字符呢?

攻击者可能会这样输入:

username = admin' --
password = (随便填)

那么最终SQL语句变成:

SELECT * FROM users WHERE username = 'admin' -- ' AND password = 'xxxxx';

这里发生了什么?

  • -- 是SQL中的注释符号,它会让后面代码(AND password='xxxxx')变成无效的注释

  • 结果就变成:

    SELECT * FROM users WHERE username = 'admin'

    相当于直接查询 admin 用户,而不检查密码! 😱

  • 这样攻击者就可以绕过密码验证,直接登录 admin 账号!✅

  • 🌟 现实世界的比喻

  • 💡 想象你在银行办理取款业务,柜员要核对你的身份:

  • 正常情况:
    柜员问你:请告诉我你的用户名密码,如果正确,我就给你取钱。

    • 你说:“我是 admin,密码是 123456

    • 银行查了一下,发现你的用户名和密码匹配,于是让你取钱。✅

  • 被攻击的情况(SQL注入):
    攻击者说“我是 admin,但是密码这部分不重要,你不用检查。”

    • 银行糊涂了,以为你就是 admin,直接给你取钱!

    • 🌟 关键点总结

    • 1️⃣ SQL 注入的本质:利用特殊字符破坏 SQL 语句结构,让数据库执行本不应该执行的代码。
      2️⃣ 常见注入方式

    • 单引号 '(破坏 SQL 结构)

    • --(注释掉后续代码)

    • OR 1=1(让查询条件永远成立) 

    • 3️⃣ 为什么 SQL 注入危险?

    • 可以绕过密码验证,直接登录

    • 可以获取数据库里的所有数据(用户信息、密码、银行卡号)

    • 甚至可以删除数据,破坏整个系统! 😱

    • 🌟 2. 什么是预编译(Prepared Statement)?

      🔹 预编译的作用

      预编译(Prepared Statement)的核心思想是: 👉 把 SQL 语句和用户输入的参数分开处理,防止用户输入的数据被当成 SQL 代码执行。

      就像去餐馆点菜时,菜谱是固定的,顾客只能填菜名,不能改动菜单的内容,这样就不会有欺骗行为。


      🔹 普通的 SQL 语句(容易被 SQL 注入攻击)

      🚨 下面是一个 危险的 SQL 代码
    • $name = $_GET['name'];  
      $query = "SELECT * FROM users WHERE name = '$name'";
      $result = $pdo->query($query);

      👆 这里的问题是:

    • $name 直接拼接到 SQL 语句中,如果用户输入了恶意代码,就会被数据库当成 SQL 代码执行,导致 SQL 注入!

    • ✅ 使用预编译(防止 SQL 注入)

      $stmt = $pdo->prepare('SELECT * FROM users WHERE name = ?');
      $stmt->execute([$name]);

      execute([$name]);

      个代码是安全的! 为什么?

          prepare('SELECT * FROM users WHERE name = ?') 这一步先定义好 SQL 语句,但不插入具体的值。

          execute([$name]) 这一步才把 $name 作为普通字符串插入,不会被当成 SQL 代码。

      💡 无论用户输入什么,它都会被当成普通文本,不会影响 SQL 语句本身。

    • 🌟 3. 为什么预编译不能 100% 防 SQL 注入?

      虽然预编译能防止大部分 SQL 注入,但在某些特殊情况下,仍然可能被绕过。
      下面是三个真实案例,让你彻底理解!😱

    • 🚨 案例一:宽字节注入

      🌍 发生场景
      某些数据库(比如 MySQL)在处理GBK 编码时,可能会错误地解析特殊字符,从而导致 SQL 注入。

      💻 代码示例

    • $pdo->query('SET NAMES gbk');  // 设定 GBK 编码
      $var = "\xbf\x27 OR 1=1 /*";    // 特殊构造的字符串
      $query = 'SELECT * FROM test WHERE name = ? LIMIT 1';
      $stmt = $pdo->prepare($query);
      $stmt->execute([$var]);

      ❓ 为什么会有问题?

      1️⃣ \xbf\x27 在 GBK 编码下,可能会被误解析为一个单独的字符
      2️⃣ 剩下的部分 "OR 1=1 /*" 会被数据库当成 SQL 代码执行!
      3️⃣ 这样就变成:

    • SELECT * FROM test WHERE name = '某些字符' OR 1=1 /*

      OR 1=1 永远为真,所以查询会返回所有数据,导致信息泄露! 😱

    • 🚨 案例二:表名注入

      🌍 发生场景
      预编译只能防止SQL参数注入,但如果动态拼接SQL,还是会有风险!😨

      💻 代码示例

    • $dbh = new PDO("mysql:host=localhost;dbname=test", "root", "password");
      $name = $_GET['name'];  // 例如输入:"users; DROP TABLE users;"
      $stmt = $dbh->prepare('SELECT * FROM ' . $name . ' WHERE username = :username');
      $stmt->execute([':username' => $_REQUEST['username']]);

      ❓ 为什么会有问题?

      1️⃣ $name 直接拼接进 SQL 语句,而不是作为参数传入 prepare()
      2️⃣ 攻击者可以输入恶意表名,比如:

    • users; DROP TABLE users;

      3️⃣ 这样 SQL 语句变成:

    • SELECT * FROM users; DROP TABLE users; WHERE username = 'admin'

      🔴 结果:users 表被删除!数据丢失! 😱

    • 案例三:ORDER BY 注入

      🌍 发生场景
      有些 SQL 语句的排序字段不能使用预编译参数,这会导致 SQL 注入。

      💻 代码示例

    • $stmt = $dbh->prepare('SELECT * FROM foo ORDER BY :userSuppliedData');
      $stmt->execute([':userSuppliedData' => $_GET['sort']]);

      为什么会有问题?

      1️⃣ ORDER BY 后面的字段名 不能使用预编译参数
      2️⃣ 攻击者可以输入:

    • id DESC; DROP TABLE foo;

      3️⃣ 这样 SQL 语句变成:

    • SELECT * FROM foo ORDER BY id DESC; DROP TABLE foo;

      4️⃣ 🔴 结果:foo 表被删除!数据库数据被破坏! 😱

      🌟 4. 如何完全防止 SQL 注入?

      虽然预编译是一个很好的安全措施,但它并不能 100% 防止 SQL 注入。
      所以,我们还需要额外的安全措施!👇


      方法 1:严格限制输入格式

      💡 不要让用户输入影响 SQL 结构的内容!
      🔹 例如,限制表名、列名、排序字段只能从“白名单”中选择!

    • $allowedSortFields = ['id', 'name', 'date'];  
      if (!in_array($_GET['sort'], $allowedSortFields)) {  
          die("Invalid input");  // 直接终止,防止 SQL 注入  
      }

      方法 2:使用 ORM 框架

      🔹 ORM(Object-Relational Mapping) 框架(比如 Laravel 的 Eloquent、Doctrine)会自动处理 SQL 语句,默认带有安全检查

      示例:

    • User::where('name', $name)->first();

      ORM 会自动处理 SQL 注入问题,不需要手动写 SQL 语句。

      方法 3:最小权限原则

      🔹 不要使用数据库管理员账户(如 root)运行 SQL 语句! 🔹 为应用创建权限受限的数据库账户,这样即使有 SQL 注入,也不会破坏整个数据库

      CREATE USER 'webapp'@'localhost' IDENTIFIED BY 'securepassword';
      GRANT SELECT, INSERT, UPDATE, DELETE ON testdb.* TO 'webapp'@'localhost';

      这样,即使黑客注入了 DROP TABLE users;,也无法执行,因为 webapp 账号没有删除表的权限!😃


      🌟 总结

      预编译是 SQL 防注入的核心方法,但并不 100% 安全。
      SQL 注入绕过的三种方式:

    • 宽字节注入(特殊字符编码问题)

    • 表名注入(拼接动态 SQL )

    • ORDER BY 注入(排序字段不能预编译
      想要 100% 防 SQL 注入,还需要额外措施!
      最佳安全做法:

    • 严格限制用户输入

    • 使用 ORM 框架

    • 遵循最小权限原则












    •  
文章来源:https://blog.csdn.net/Aishenyanying33/article/details/146527157
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ppmy.cn/ops/170170.html

相关文章

Metal 着色器与渲染管线

Metal 着色器与渲染管线:从 .metal 文件到 MTLRenderPipelineState 引言 在 iOS 和 macOS 开发中,Metal 是苹果提供的强大图形和计算 API,允许开发者直接访问 GPU 进行高性能的图形渲染和并行计算。本文将深入探讨 Metal 着色器文件&#x…

C++代码规范

c代码规范 总体原则类和函数设计指导原则、保证静态类型安全、保证内存安全、遵循CISO标准、优先编译时检查错误、在编译时无法实施的检查,在运行时检查、使用命名空间来限定作用域、优先使用C特性而不是c特性,并且优先使用标准库静态类型安全静态安全类…

纯css实现环形进度条+动画加载效果

写在最前面: 本文是小程序开发中,使用纯csshtml实现的进度圆环动画加载效果(换成vue也是一样的)。 如果你的项目可以用echarts,建议还是用插件,手搓不易,这很难评。 实现效果如上图:…

从车间到数字生态:MES如何引领制造业智能化革命‌

在全球制造业加速迈向工业4.0的浪潮中,传统生产模式正经历颠覆性变革。制造执行系统(MES)作为连接物理车间与数字世界的核心纽带,正从“生产辅助工具”升级为“智能决策大脑”,推动制造业向数据驱动、柔性化与可持续化…

gradio调用多个CSS的HTML页

很多博客介绍的gradio读取html和css比较简单,如果要做很细致的前端页面优化,比如丰富的响应式的cssjs,至少要有html多个css,是暂不能实现的。bootstrap、font-awesome、jquery等 方案一当然是直接更换htmlcss为主的部署方式&#…

前端国际化-插件模式

文章目录 Webpack 插件开发解析中文调用有道翻译 API生成 JSON 语言文件React 国际化实现 Webpack 插件开发 创建 i18n-webpack-plugin.js 插件:在 src 目录下扫描所有文件使用 babel-parser 解析 JavaScript/JSX 代码识别中文文本通过有道翻译 API 翻译生成 local…

涨薪技术|Kubernetes(k8s)环境部署实战

01准备工作 1)修改主机名 hostnamectl set-hostname masterbash #更新主机名 2)关闭所有机器的swap分区 sudo swapoff -a#修改/etc/fstab,注释掉swap行sudo vi /etc/fstab 3)配置固定ip地址 #配置路径cd /etc/sysconfig/netw…

网络安全基础:五类安全服务、八种安全机制与OSI七层模型的全面解析

目录 引言 五类安全服务 2.1 认证服务 2.2 访问控制 2.3 数据保密性 2.4 数据完整性 2.5 不可否认性 八种安全机制 3.1 加密机制 3.2 数字签名 3.3 访问控制机制 3.4 数据完整性机制 3.5 认证交换机制 3.6 流量填充机制 3.7 路由控制机制 3.8 公证机制 OSI七层…