当前位置: 首页 > news >正文

从SQL的执行流程彻底详解预编译是如何解决SQL注入问题

传统(不安全)的 SQL 执行流程(直接拼接字符串):

  1. 连接器 (Connector): 客户端连接成功,获得权限。

  2. (跳过查询缓存): 假设缓存未命中或未使用。

  3. 分析器 (Analyzer):

    • 应用程序将拼接好的、可能包含恶意输入的完整 SQL 字符串(如 "SELECT user_id FROM users WHERE username = '' OR '1'='1' -- ' AND password = '...';"​)发送给 MySQL 服务器。
    • 词法分析: 将整个字符串拆分成 Token。OR​, '1'​, =​, '1'​, --​ 都会被识别为独立的 Token。
    • 语法分析: 这是关键点! 分析器根据语法规则,将这些 Token 构建成一个抽象语法树 (AST)。由于 ' OR '1'='1' -- ​ 符合 SQL 语法(一个 OR 条件和一个注释符),它会被成功地解析并融入 AST 的逻辑结构中。此时,用户输入已经扭曲了原始 SQL 的意图。
  4. 执行器 (Executor):

    • Prepare 阶段: 检查被扭曲后的 AST 中涉及的表、字段是否存在,并验证权限。
    • Optimize 阶段: 优化器根据这个被注入、扭曲了的 AST 生成执行计划。它会发现 '1'='1'​ 是恒真条件,并且 --​ 注释掉了后续条件,从而生成一个可能绕过验证的、非预期的执行计划。
    • Execute 阶段: 执行器按照这个恶意的执行计划去调用存储引擎接口。它可能会告诉存储引擎:“给我所有用户的 user_id,因为条件是 username = '' OR TRUE​”。
  5. 存储引擎 (Storage Engine): 根据执行器基于恶意计划发出的指令,返回了非预期的数据(比如所有用户的 ID)。

使用预编译语句(Prepared Statements)的安全流程:

这个过程分为两个主要阶段:准备 (Prepare) 和 执行 (Execute)。

阶段一:准备 (Prepare)

  1. 连接器 (Connector): 客户端连接成功,获得权限。(同上)

  2. 应用程序发送 SQL 模板: 客户端发送的是带有占位符的 SQL 模板(如 "SELECT user_id FROM users WHERE username = ? AND password = ?;"​)给 MySQL 服务器,请求进行“准备”。注意:此时不包含任何用户输入的数据!

  3. (跳过查询缓存): 准备语句通常不会利用查询缓存。

  4. 分析器 (Analyzer):

    • 词法分析: 将模板拆分成 Token,?​ 被识别为占位符。
    • 语法分析: 只针对模板进行分析。检查模板的语法是否正确,并构建一个代表模板结构的 AST。这个 AST 清晰地知道 username = ?​ 和 password = ?​ 是两个独立的比较条件,?​ 的位置是需要填入数据值的地方。此时用户输入完全没有参与,AST 的结构是固定的、安全的。
  5. 执行器 (Executor) - Prepare & Optimize 阶段:

    • Prepare 阶段: 检查模板中涉及的表、字段是否存在,验证权限。
    • Optimize 阶段: 优化器根据这个安全的、基于模板的 AST 生成一个参数化的执行计划,并缓存起来。这个计划知道它需要比较 username​ 和 password​ 列,并等待具体的值。

阶段二:执行 (Execute)

  1. 应用程序发送参数: 客户端发送执行指令,同时单独发送用户输入的数据(如 ' OR '1'='1' -- ​ 和 any_password​)作为参数,并指明这些参数对应模板中的哪个占位符。

  2. 服务器接收参数: MySQL 服务器接收到执行指令和参数列表。

  3. 执行器 (Executor) - Execute 阶段:

    • 跳过分析器: 参数不再经过分析器的词法和语法分析阶段来构建 AST。数据库已经知道 SQL 的结构了。
    • 调用优化好的计划: 执行器调出在“准备”阶段生成并缓存的那个安全的、参数化的执行计划。
    • 绑定参数: 将接收到的参数值(' OR '1'='1' -- ​ 和 any_password​)仅仅作为数据,填充到执行计划中对应的位置。
    • 执行: 执行器按照安全的计划调用存储引擎接口。它会明确地告诉存储引擎:“请查找 username​ 列的值严格等于字符串数据 ' OR '1'='1' -- '​ 并且 password​ 列的值严格等于字符串数据 any_password​ 的记录”。
  4. 存储引擎 (Storage Engine): 接收到执行器的指令,将传入的参数仅仅当作需要比较的数据字面量进行查找。由于找不到 username​ 完全匹配 ' OR '1'='1' -- '​ 的记录,查询失败。

核心区别与防止注入的原因总结:

关键在于分离处理:

  • 预编译阶段: SQL 的结构(代码逻辑)在没有用户数据干扰的情况下,通过分析器被一次性确定、解析、优化并固化为安全的执行计划。
  • 执行阶段: 用户输入的数据作为独立的参数被发送,它们绕过了分析器对 SQL 结构的解析,直接被执行器当作纯粹的数据值代入到预先定义好的安全执行计划中。

因为用户输入的数据没有机会在分析器阶段影响或改变 SQL 的语法结构 (AST),所以它无法注入恶意的 SQL 逻辑,从而有效防止了 SQL 注入攻击。

http://www.xdnf.cn/news/331093.html

相关文章:

  • Linux57配置MYSQL YUM源
  • 离散化(竞赛)
  • MinIo安装和使用操作说明(windows)
  • C++相关学习过程
  • 《USB技术应用与开发》第七讲:CDC串口设备案例
  • 【AlphaFold2】深入浅出,讲解Evoformer|学习笔记
  • 【汇正自控阀门集团】签约智橙PLM,智橙助泵阀“以国代进”
  • ntdll!CsrServerApiRoutine函数--csrsrv!CsrCallServerFromServer什么时候被调用?
  • 计算机硬件(南桥):主板芯片组FCH和PCH的区别
  • 苍穹外卖(用户下单、订单支付)
  • 当体育数据API遇上WebSocket:一场技术互补的「攻防战」
  • UGUI如何使用EventTrigger
  • LeetCode105_从先序与中序遍历序列构造二叉树
  • 如何从路由表优化的角度理解[CIDR]无类别域间路由选择技术?
  • 六级阅读---2024.12 卷一 仔细阅读1
  • 【编译原理】第五章 自下而上语法分析
  • 快速上手SpringBoot开发指南
  • 力扣热题100之反转链表
  • Linux系统Shell脚本之shell数组、正则表达式、及AWK
  • Mongo3.4升级到mongo6性能降低9倍
  • HSV颜色空间
  • 51camera将参加第九届沥青路面论坛暨新技术新成果展示会
  • 代码随想录算法训练营第三十三天(补)
  • Unity Gizmos
  • 题解 洛谷 Luogu P1073 [NOIP 2009 提高组] 最优贸易 强连通分量 Tarjan 缩点 拓扑排序 动态规划 C++
  • Vue与Python的深度整合:构建现代Web应用的全栈范式
  • 国标GB28181设备管理软件EasyGBS打造明厨亮灶食品安全监管防线
  • 对称二叉树(简单)
  • sqlite数据库操作
  • Qt开发:枚举的介绍和使用