SQL注入理解及防范

避免SQL注入的一般原则是:不信任用户提交的数据。

一、什么是“SQL注入”?

所谓SQL注入(sql inject),具体来说,是利用现有应用程序,将(恶意的)SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。

典型例子

假如 user 表中有用户名为 123456 ,密码为 123456 的记录,而在前台页面提交表单的时候用户输入的用户名和密码是随便输入的,这样当然是不能登录成功的。

但是如果后台处理的 SQL 语句是如上所写,前台页面用户名也是随便输入,而用户输入的密码是这样的 aaa’ or ‘1’='1 ,处理登录的 SQL 语句就相当于是这样的:

SELECT USERNAME,PASSWORD FROM USER WHERE USERNAME='123456' AND PASSWORD='aaa' or '1'='1';

我们知道,1=1 是 true,所以上面这个 SQL 语句是可以执行成功的,这是一个 SQL 注入问题。


二、如何防止“SQL注入”

1、SQL预编译技术

解决 SQL注入 问题的这个方案的关键要点实际上是将SQL语句和用户输入的查询数据分别进行处理,而不是一视同仁的作为SQL语句的不同部分进行拼接处理。

以 MySQL 为例,在 MySQL 中,所谓预编译其实是指先提交带占位符的 SQL 模板,然后为其指定一个 key,MySQL 先将其编译好,然后用户再拿着 key 和占位符对应的参数让 MySQL 去执行。

使用这样的SQL预编译技术,除了可以防止SQL注入外,还可以对预编译的SQL语句进行缓存,之后的运行就省去了解析优化SQL语句的过程,可以加速SQL的查询效率。

一个标准的预编译SQL的用法如下:

prepare prepare_query from 'select * from s_user where username = ?' # 提交带有占位符的参数化 SQL,也可以理解为 SQL 模板
set @name = '%王五'; # 指定一个参数
execute prepare_query using @name; # 指定参数化 SQL 的 key 和参数,让 MySQL 自己去拼接执行

先通过 prepare 设置一个 SQL 模板,然后通过 execute 提交参数,MySQL 会自行根据参数替换占位符,到最后执行的 SQL 就是:

select * from s_user where username = '%王五'

工程实践举例:
在 Gorm 中,就为我们封装了SQL预编译技术,可以供我们使用:

db = db.Where("merchant_id = ?", merchantId)

预编译的原理大白话

按网上的说法,prepare 执行的时候实际上 SQL 已经编译完了,所以可以防止注入,因为后续不管塞什么参数都不可能在调整语法树了。

对于预编译SQL来说,我们作为模板的参数化SQL已经完成的编译过程,这段SQL包含几条有效语句?查哪张表?查哪些字段?作为条件的字段有哪些?…这些在 prepare 语句执行完后就固定下来了,此后我们再通过 execute 语句塞进去的任何参数,都会进行转义,不会再作为SQL的一部分。这就是为什么说预编译SQL可以防止注入的原因。

2、对用户提交的数据进行校验

2.1 利用正则表达式校验

2.2 利用字符串特殊字符校验

更贴合实际的业务场景,可针对性处理。


参考:
        https://www.cnblogs.com/Createsequence/p/16963891.html
        https://blog.csdn.net/qq_39384184/article/details/108144309


你可能感兴趣的:(MySQL,web,sql,数据库,web安全)