预编译为什么能防止SQL注入?一看你就明白了。预编译原理详解

这篇具有很好参考价值的文章主要介绍了预编译为什么能防止SQL注入?一看你就明白了。预编译原理详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

「作者主页」:士别三日wyx
「作者简介」:CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者
「推荐专栏」:对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》

先简单了解一下SQL注入的过程。

比如一个查询功能,根据用户输入的id,查询用户名和密码。

预编译为什么能防止SQL注入?一看你就明白了。预编译原理详解,《网络安全快速入门》,sql,数据库,安全,机器学习,人工智能

后台的SQL语句是这样的

select *from user where id='1'

如果我们在参数中提交payload

 https://127.0.0.1/Less-1/?id=-1' union select 1, 2, user()-- a

后台的SQL就会拼接成这样(这里重点注意:SQL的语法结构被改变了)

select *from user where id='-1' union select 1, 2, user()-- a'

帮我们查到数据库的管理员账号,导致了SQL注入。

预编译为什么能防止SQL注入?一看你就明白了。预编译原理详解,《网络安全快速入门》,sql,数据库,安全,机器学习,人工智能


从注入的过程中我们可以发现,SQL注入的核心是:用户输入的参数改变了SQL的语法结构。

而预编译,可以防止语法结构被改变。在讲预编译之前,我们得先了解下SQL的执行过程。


1、SQL执行过程

以MySQL为例,数据库在执行SQL语句时,需要经历7个步骤:

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

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

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

2、预编译原理

预编译最初的目的是提高代码的复用性,因为有很多只有参数值不同的SQL(完全相同的SQL会从缓存里查),比如:

select * from user where id='1'
select * from user where id='2'

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

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

select * from user where id={占位符}

通过抓包来看,SQL语句先被预编译(Prepare Statement),参数值先用占位符替代。等执行(Execute Statement)的时候,再传入参数。

预编译为什么能防止SQL注入?一看你就明白了。预编译原理详解,《网络安全快速入门》,sql,数据库,安全,机器学习,人工智能

用户传入的参数不参与语法树的构建,就改不了SQL的语法结构,也就避免了注入。

扩展:

PHP的PDO(PHP Data Object)是操作多种数据库的统一接口,提供了两种预编译机制:本地预编译和模拟预编译。
本地预编译是指数据库自身进行预编译,也是我们这里提到的预编译方式。
模拟预编译则用于那些不支持预编译的数据库,本质上是在底层先对用户的输入进行转译,再对SQL语句进行拼接,然后把完整的SQL语句发给数据库执行。
转译后的参数只会当做字符串处理,无法参与SQL的编译(在PHP 5.3.6前,使用单字节字符集转译,存在单字节注入)正确设置字符集,也可以防止SQL注入。


3、预编译防止SQL注入

以 MyBatis(半自动化的持久层框架)为例,#{id}这种格式传参,会先把SQL传给数据库进行预编译,等调用的时候,再用参数替换掉占位符,然后执行。

<select id="getUser" resultType="Blog" parameterType=int>
         SELECT *
         FROM user
		 WHERE id=#{id}
</select>

但有些SQL需要使用动态表名和列名,这种时候就不能使用预编译了,需要把#{id}换成${id},这样参数就会直接参与SQL编译,无法防止SQL注入,这时候就要手动过滤参数了。

提示:MyBatis框架的预编译,是JDBC中的PreparedStatement类在起作用,它的对象包含了编译好的SQL语句。

PHP中使用MySQL的预编译功能:

1)定义预编译的SQL语句,参数用占位符 ? 表示

$sql = "SELECT * FROM user WHERE id= ? ";

2)创建预处理对象

$mysqli_stmt = $mysqli->prepare($sql);

3)绑定参数

$mysqli_stmt->bind_param('i', $id);

4)绑定结果集

$mysqli_stmt->bind_result($username);

5)执行

$mysqli_stmt->execute();

4、预编译的局限性

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

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

同理,排序场景的ASC/DESC也需要动态传参,不能使用预编译。文章来源地址https://www.toymoban.com/news/detail-733426.html

到了这里,关于预编译为什么能防止SQL注入?一看你就明白了。预编译原理详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • JVM执行引擎——为什么Java是半编译半解释语言

            起初设计者的初衷是将字节码文件翻译为机器语言的指令来执行即可,就诞生了解释器。但是采用一行行来解释的 效率比较低 ,JIT编译器会将编译后的机器码做一个缓存的操作,放在方法区的JIT代码缓存中,是否需要启用JIT编译器直接将字节码编译为机器码,则

    2024年02月15日
    浏览(51)
  • 为什么SQL日志文件很大,该如何处理?

    SQL Server 日志文件是记录所有数据库事务和修改的事务日志文件。用 SQL 术语来说,此日志文件记录对数据库执行的所有 INSERT 、 UPDATE 和 DELETE查询操作。 如果数据库联机或恢复时日志已满,SQL Server 通常会发出 9002 错误。在这种情况下,数据库只能读取而不能更新。此篇文章

    2024年02月06日
    浏览(66)
  • C++中,C::C::C::C::foo() 为什么编译成功?

    有人问: 为什么 最后那行: 能编译成功?这是什么规则? 嗯…… Entity::Entity::Entity::Entity::Entity::Entity::foo() 竟然编译成功?这一切的背后,是人性的扭曲,还是道德的沦丧? 敬请关注今晚八点 CPPTV 12 频道,让我们跟随镜头走进厚厚的C++标准文档…… 这个案例,至少牵涉到

    2024年02月12日
    浏览(55)
  • 面试官灵魂拷问:为什么 SQL 语句不要过多的 join?

    在SQL中,JOIN是一种用于将两个或多个表中的数据行连接在一起的操作。JOIN操作通过查找这些表之间的共同列,并将它们彼此匹配来实现。 JOIN操作有多种类型,包括 INNER JOIN、LEFT JOIN、RIGHT JOIN、FULL OUTER JOIN 等,其中 INNER JOIN 是最常见的类型。它将两个表中的行进行匹配,只

    2023年04月09日
    浏览(49)
  • scanf和strcpy这类关键字和函数为什么不安全,使用VS编译会报错

    首先先说解决方法: 在程序最顶端加入这个代码段 这主要是微软的 C 运行时库实现将这些函数标记为不安全,主要原因是这些函数缺乏对输入长度的边界检查,容易导致缓冲区溢出漏洞。 会产生这样的报错: 即: C4996    \\\'strcpy\\\': This function or variable may be unsafe. Consider usin

    2024年02月13日
    浏览(49)
  • C语言辨析——int a=5;为什么++a=1能编译通过而a++=1不行呢?

    1. 问题 有人问:int a=5; 为什么++a=1能编译通过a++=1编译错误呢? 解释:不管是++a=1还是a++=1在C编译环境下都无法编译通过,但在C++中,++a=1可以编译通过,而a++=1无法编译通过,这也是C和C++的一个不同。因此,这是一个关于 C++的问题 。 2. 分析 不管是C还是C++,语句a++=1;的

    2024年01月16日
    浏览(55)
  • 【C语言】scanf和strcpy这类关键字和函数为什么不安全,使用VS编译会报错

    首先先说解决方法: 在程序最顶端加入这个代码段 这主要是微软的 C 运行时库实现将这些函数标记为不安全,主要原因是这些函数缺乏对输入长度的边界检查,容易导致缓冲区溢出漏洞。 会产生这样的报错: 即: C4996    \\\'strcpy\\\': This function or variable may be unsafe. Consider usin

    2024年02月14日
    浏览(59)
  • 【MyBatis】防止sql注入

    前言 关于sql注入的解释这里不再赘述。 在MyBatis中防止的sql注入主要分为两种:         第一种就是MyBatis提供了两种支持动态 sql 的语法 #{} 和 ${},其中${} 是简单的字符串替换,而 #{} 在预处理时,会把参数部分用一个占位符 ? 代替,可以有效的防止sql的注入,面试的时

    2024年02月13日
    浏览(51)
  • SQL防止注入工具类,可能用于SQL注入的字符有哪些

    SQL注入是一种攻击技术,攻击者试图通过在输入中注入恶意的SQL代码来干扰应用程序的数据库查询。为了防止SQL注入,你需要了解可能用于注入的一些常见字符和技术。以下是一些常见的SQL注入字符和技术: 单引号 \\\' ​: 攻击者可能会尝试通过输入 ​ ​\\\'​ ​ 来结束 SQL 查

    2024年02月21日
    浏览(43)
  • 【Linux操作系统】编译过程中遇到的问题-为什么加-c?执行文件提示无法执行二进制文件?main函数参数argc和*argv[]的作用和理解?

    在使用GCC编译器进行程序开发时,我们经常会遇到一些编译过程中的问题, 比如为什么要加上\\\"-c\\\"选项,以及为什么生成的可执行文件无法执行等问题。 本篇博客将详细介绍这些问题,并给出相应的代码和解释,帮助读者更好地理解GCC编译过程中的\\\"-c\\\"选项和main函数的参数a

    2024年02月12日
    浏览(69)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包