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

为什么SQL预编译可以防止SQL注入攻击

前言

防范SQL注入攻击是每一位做后端开发的程序员必须会的基本功。本文介绍其中一种防范攻击的方法:SQL预编译。

本文大部分内容引用自这篇文章,部分内容有修改。

注入例子

先简单回顾下SQL注入攻击的过程,假设有一个SQL语句:

SELECT * FROM users WHERE id = '{$p}';

{$p}是用户传递过来的查询参数,假设用户传递的参数是123,则SQL会是:

SELECT * FROM users WHERE id = '123';

但如果用户传递的参数是';DROP TABLE users;-- ,SQL就会变成:

SELECT * FROM users WHERE id = '';DROP TABLE users;-- ';

原本一个简单的SELECT语句,通过精心构造查询参数,就让它变成了一个删除users表的语句!

从注入的过程可以发现,如果用户传递过来的参数,我们不做任何处理就拼接到SQL语句中,很容易就会让黑客改变我们SQL语句的语法结构,引发严重事故。

解决方法

一、对用户参数进行转义

对一些有特殊意义的字符,例如单引号,进行转义,转义后再去数据库查询,相信很多人都知道这种做法,本文就不详细讲了。

二、SQL预编译

本文说的预编译,是指在数据库端进行的预编译。有部分代码库的预编译是在客户端本地进行的,这种是虚假的“预编译”。

通过SQL预编译,可以防止语法结构被改变。先了解下SQL的执行过程:

  1. 词法分析:将SQL语句分解成一个个token(关键字、标识符、运算符),然后对token进行分类和解析,生成相应的数据结构。
  2. 语法分析:根据SQL语法检测规则检查语法是否正确,并成成语法树。
  3. 语义分析:遍历语法树,确定表和列等信息,同时检查语义的正确性。
  4. 优化处理:使用优化器对SQL语句进行处理和优化,比如执行计划、索引等。
  5. 执行计划:使用执行计划生成器生成SQL语句的执行计划,比如数据的访问方式,索引的使用方式等。
  6. 引擎执行:将执行计划发送给相应的数据库引擎进行处理,执行计划被翻译成底层的操作指令,执行数据扫描、索引查找、排序、分组等操作。
  7. 返回数据:将执行结果返回给客户端,比如查询结果集或操作结果。

在这里,我们粗暴的把执行过程理解成两步,即:先编译SQL语法结构(1~3步),再执行SQL语句(4~7步)。

正常情况下,用户输入的参数会直接参与SQL语法的编译,而预编译则是先构建语法树,确定SQL语法结构以后,再拼接用户的参数。

2.1 预编译原理

预编译最初的目的是提高SQL语句的执行效率,因为有很多语法结构相同,但只有参数值不同的SQL,比如:

SELECT * FROM users WHERE id = '1';
SELECT * FROM users WHERE id = '2';

这些SQL的语法树相同,但每次都要进行重复的编译,很浪费时间。

而预编译可以将SQL语句模板化,值的位置用占位符替代,这样数据库就会事先编译好SQL语法结构,等真正调用的时候,再传入参数值执行,省掉了重复建立语法树的时间。

SELECT * FROM users WHERE id = {占位符}

因为语法树已经建立好了,要查询什么表、查询字段是哪些、有多少个查询条件等等这些全都已经确定好了,用户传入的参数不参与语法树的构建,就改不了SQL的语法结构,也就避免了注入。

2.2 预编译的局限性

预编译的机制是先编译,再传值,用户传递的参数无法改变SQL语法结构,从根本上解决了SQL注入的问题。

但并不是所有参数都可以使用预编译,比如动态表名和列名的场景,因为语义分析时,会解析语法树,检查表名和列名是否存在,所以表名和列名不能被占位符替代,也就无法使用预编译。

同理,排序场景的ASC/DESC也不能使用预编译。

参阅

  • 预编译为什么能防止SQL注入?一看你就明白了。预编译原理详解
  • 预编译SQL为什么能够防止SQL注入
http://www.lryc.cn/news/177305.html

相关文章:

  • 基于体系结构-架构真题2022(四十一)
  • 【uniapp+vue3 】页面加载时根据不同角色设置导航栏标题
  • 不讲故事的设计模式-模板方法模式
  • 基于SpringBoot的酒店客房管理系统
  • 消息队列-RabbitMQ(二)
  • 程序通过命令行获取操作系统名称+版本+CPU名称等:Part2
  • 微软最热门的10款前端开源项目!
  • C#(CSharp)入门实践项目(简易回合制游戏)
  • GEO生信数据挖掘(五)提取临床信息构建分组,分组数据可视化(绘制层次聚类图,绘制PCA图)
  • golang时间问题汇总(用法常见问题:插入数据库时间自动+8)
  • TCP网络连接中的三次握手和四次挥手
  • 游戏服务商Latis Global参展2023 ChinaJoy B2B
  • oracle常用sql
  • 手游模拟器长时间运行后,游戏掉帧且不恢复
  • linux下离线安装telnet
  • Unity 发布WebGL平台,C#与JavaScript交互
  • 利用 Forcing InnoDB Recovery 特性解决 MySQL 重启失败的问题
  • windows修改键位F11变insert(改键盘映射)
  • 安装gpu版本的paddle和paddleclas
  • 61从零开始学Java之处理大数字相关的类有哪些?
  • vscode 搜索界面的files to include files to exclude 是什么功能?
  • 数据计算-第15届蓝桥杯第一次STEMA测评Scratch真题精选
  • 谈谈前端和后端的选择
  • Vue3最佳实践 第六章 Pinia,Vuex与axios,VueUse 1(Pinia)
  • Java比较器之equals、comparable、comparator
  • Virtio-user使用简介
  • 点云从入门到精通技术详解100篇-基于深度学习的三维植物点云分割网络
  • C语言 Cortex-A7核 SPI 实验
  • Spring工具类--ReflectionUtils的使用
  • zemax西德莫尔目镜