为什么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.mzph.cn/news/89210.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【面试必备】缓存的更新策略-缓存雪崩-缓存穿透-缓存预热-缓存击穿~

目录 1、什么是缓存 2、为什么使用Redis作为MySQL的缓存 3、缓存的更新策略 3.1、策略一:定期生成 3.2、策略二:实时生成 内存淘汰策略【面试重点】 4、缓存预热(Cache preheating)【面试重点】 5、缓存穿透(Cache penetration)【面试重点】 6、…

java 入门-使用eclipse、javaFX、SceneBuilder进行图形界面开发

个人是 一直在开C# CS端开发 , 目前 公司的软件 基本都使用了java作开发。 为了更好适应环境,我也只能再次学习这个陌生的开发工具。 java 的开发界面非常不友好 ,对于我这样的初学者只能是借助插件来进行界面与后台联动, 上网度…

识别车牌的代码分享

接口 接口为车牌的自动定位和识别,返回地域编号和车牌号车牌颜色: # pip install poocr import poocr # 可以填写本地图片的地址:img_path,也可以填写在线图片的地址:img_url # 如果2个都填,则只用在线图片img_url # configPath是配置文件的信息,可以不填 Number…

Redis缓存雪崩、击穿、穿透

文章目录 Redis缓存雪崩产生缓存雪崩原因缓存雪崩解决方案缓存雪崩案例,以及如何解决 Redis缓存击穿产生缓存击穿原因缓存击穿解决方案缓存击穿案例,以及如何解决 Redis缓存穿透产生缓存穿透原因缓存穿透解决方案缓存穿透案例,以及如何解决 R…

找高清、4K图片素材就上这6个网站,免费下载!

不会还有人找图片素材直接上网去搜吧,告诉你们6个网站,轻松找到想要的图片素材,不仅质量高,还可以免费下载,重点是还可以商用。赶紧收藏起来吧~ 1、菜鸟图库 https://www.sucai999.com/pic.html?vNTYwNDUx 网站主要为…

Scrapy+Selenium自动化获取个人CSDN文章质量分

前言 本文将介绍如何使用Scrapy和Selenium这两个强大的Python工具来自动获取个人CSDN文章的质量分数。我们将详细讨论Scrapy爬虫框架的使用,以及如何结合Selenium浏览器自动化工具来实现这一目标。无需手动浏览每篇文章,我们可以轻松地获取并记录文章的…

查询PCIE设备的VID,DID,SVID,SDID

查询PCIE设备的VID,DID,SVID,SDID ( Vendor ID、 Device ID、Subsystem Vendor ID、Subsystem Device ID ) [rootlocalhost ~]# lspci -s 04:00.0 -xxxvvv 04:00.0 Ethernet controller: Intel Corporation I210 Gigabit Network Connection (rev 03)C…

【JAVA】读取classpath下的文件

在Java中从classpath读取文件,可以使用下面的方法: 使用ClassLoader获取classpath资源作为流读取: InputStream input this.getClass().getClassLoader().getResourceAsStream("config.properties");使用Class的getResourceAsStream方法读取classpath资源: Input…

Docker部署ElasticSearch数据库+analysis-ik分词器插件

文章目录 一、部署ElasticSearch数据库二、添加分词器插件(analysis-ik)三、测试ElasticSearch数据库analysis-ik分词器插件 一、部署ElasticSearch数据库 1、准备工作 docker pull docker.elastic.co/elasticsearch/elasticsearch:7.17.6 Pwd"/data/software/elasticse…

Casper Network 构建企业级区块链生态的野望

Casper Network 是基于 Layer1 且图灵完备 Wasm 的智能合约平台,它由唯一可操作的 CBC-Casper Proof-of-Stake (PoS) 共识算法(称为 Highway)支持,该网络是一个无需许可、去中心化的公共区块链。 Casper Network 主网在 2021 年 4…

架构案例-架构真题2016(四十)

(2016)嵌入式处理器是嵌入式系统的核心部件,一般可分为嵌入式微处理器(MPU)微控制器(MCU)、数字信号处理器(DSP)和片上系统(SOC)。以下叙述中&…

一篇文章让你熟悉unordered_map及其模拟实现

熟悉unordered_map及其模拟实现 unordered_map的定义1. unordered_map的模板定义2. unordered_map的成员类型 unordered_map构造函数unordered_map赋值运算符重载unordered_map容量函数(Capacity)unordered_map迭代器(Iterators)1…

慢性疼痛治疗服务公司Kindly MD申请700万美元纳斯达克IPO上市

来源:猛兽财经 作者:猛兽财经 猛兽财经获悉,慢性疼痛治疗服务公司Kindly MD近期已向美国证券交易委员会(SEC)提交招股书,申请在纳斯达克IPO上市,股票代码为(KDLY),Kindly MD计划通过…

通信协议:Uart的Verilog实现(下)

4、UART接收器 UART接收器负责接收串行比特流,去除起始位和停止位,并以并行格式将数据保存到与主机数据总线相连的寄存器里。接收器无法获得发送时钟,因此尽管数据以标准比特率到达,但数据未必与接收主机内的时钟同步。同步问题可…

面试算法13:二维子矩阵的数字之和

题目 输入一个二维矩阵,如何计算给定左上角坐标和右下角坐标的子矩阵的数字之和?对于同一个二维矩阵,计算子矩阵的数字之和的函数可能由于输入不同的坐标而被反复调用多次。例如,输入图2.1中的二维矩阵,以及左上角坐标…

【SA8295P 源码分析】100 - 获取 88Q5152 Switch Port1、Port2 端口的主从模式 / 传输速率 / 链路状态

【SA8295P 源码分析】100 - 获取 88Q5152 Switch Port1、Port2 端口的主从模式 / 传输速率 / 链路状态 1. 读取 P1、P2 端口 主从模式 / 传输速率2. 读取 P1、P2 端口 Link Status3. 读取 P1、P2 端口 Duplex 全双工/半双工模式4. 完整代码如下系列文章汇总见:《【SA8295P 源码…

leetcode Top100(24) // 环形链表2

环形链表 给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内…

python机器学习融合模型:Stacking与Blending(附代码)_论文_模型竞赛_企业建模

大家好,今天给大家总结归纳了python机器学习融合模型:Stacking与Blending(附代码)。 1 堆叠法Stacking 一套弱系统能变成一个强系统吗? 当你处在一个复杂的分类问题面前时,金融市场通常会出现这种情况&…

自定义热加载:如何不停机实现核心代码更新

文章目录 1. 常见的几种实现代码热更新的几种方式对于开发环境我们可以使用部署环境1. 使用 Arthas 的 redefine 命令来加载新的 class 文件2. 利用 URLClassLoader 动态加载3. 通过Java的Instrumentation API 也是可以实现的 2. 实现1. ClassScanner扫描目录和加载类2. 定时任…

Mybatis学习笔记7 参数处理专题

Mybatis学习笔记6 使用时的一些小技巧_biubiubiu0706的博客-CSDN博客 1.单个简单类型参数 2.Map参数 3.实体类参数 4.多参数 5.Param注解(命名参数) 6.Param源码分析 建表 插入点数据 新建模块 pom.xml <?xml version"1.0" encoding"UTF-8"?&…