golang mysql 防注入_Go,Gorm 和 Mysql 是如何防止 SQL 注入的

Go,Gorm 和 Mysql 是如何防止 SQL 注入的

SQL 注入和 SQL 预编译技术

什么是 SQL 注入

所谓SQL注入(sql inject),就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意的)SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。

SQL 注入例子

如下所示,是一个用户进行登录时,输入用户名和密码,再将数据通过表单传送到后端进行查询的 SQL 语句。

sql = "SELECT USERNAME,PASSWORD FROM USER WHERE USERNAME='" + username + "' AND PASSWORD='" + password + "'";

上面这个 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 注入的解决

上述 SQL 注入问题产生的原因就是用户的输入是包含 SQL 语句的,而且后端执行 SQL 语句时直接将用户的输入和查询的 SQL 语句进行了拼接。

因此,简单的拼接用户输入的数据和后端的查询 SQL 语句,是不可行的,我们需要将用户的输入作为一个完整的字符串,而忽略内部的 SQL 语句。当用户输入的密码是这样的 aaa’ or ‘1’='1 ,处理登录的 SQL 语句实际应该执行的是:

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

这样就可以避免 SQL 注入导致的安全漏洞。

SQL 预编译技术

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

通常我们的一条 SQL 在 DB 接收到最终执行完毕返回可以分为下面三个过程:

词法和语义解析

优化 SQL 语句,制定执行计划

执行并返回结果

但是我们可以将其中需要用户输入的值用占位符替代,可以视为将 SQL 语句模板化或者说参数化,再将这样的 SQL 语句进行预编译的处理,在实际运行的时候,再传入用户输入的数据。

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

Gorm 和 Go 端的 SQL 预编译

在 Gorm 中,就为我们封装了 SQL 预编译技术,可以供我们使用。

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

在执行这样的语句的时候实际上我们就用到了 SQL 预编译技术,其中预编译的 SQL 语句merchant_id = ?和 SQL 查询的数据merchantId将被分开传输至 DB 后端进行处理。

db = db.Where(fmt.Sprintf("merchant_id = %s", merchantId))

而当你使用这种写法时,即表示 SQL 由用户来进行拼装,而不使用预编译技术,随之可能带来的,就是 SQL 注入的风险。

Gorm 端的 SQL 预编译

// SQLCommon is the minimal database connection functionality gorm requires. Implemented by *sql.DB.

type SQLCommon interface {

Exec(query string, args ...interface{}) (sql.Result, error)

......

}

Go 端的 SQL 预编译

// src/database/sql/sql.go

func (db *DB) execDC(ctx context.Context, dc *driverConn, release func(error), query string, args []interface{}) (res Result, err error) {

......

resi, err = ctxDriverExec(ctx, execerCtx, execer, query, nvdargs)

......

if err != driver.ErrSkip {

......

return driverResult{dc, resi}, nil

}

......

si, err = ctxDriverPrepare(ctx, dc.ci, query)

......

ds := &driverStmt{Locker: dc, si: si}

......

return resultFromStatement(ctx, dc.ci, ds, args...)

}

实际的实现最终还是落到了go-sql-driver上,如下面代码所示go-sql-driver支持开启预编译和关闭预编译,由mc.cfg.InterpolateParams = false、true决定,可以看出gorm中mc.cfg.InterpolateParams = true,即开启了预编译

func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, error) {

......

if len(args) != 0 {

if !mc.cfg.InterpolateParams {

return nil, driver.ErrSkip

}

prepared, err := mc.interpolateParams(query, args)

if err != nil {

return nil, err

}

query = prepared

}

......

err := mc.exec(query)

......

return nil, mc.markBadConn(err)

}

Mysql 端的SQL 预编译

在MySQL中是如何实现预编译的,MySQL在4.1后支持了预编译,其中涉及预编译的指令实例如下

可以通过PREPARE预编译指令,SET传入数据,通过EXECUTE执行命令

mysql> PREPARE stmt1 FROM 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';

Query OK, 0 rows affected (0.00 sec)

Statement prepared

mysql> SET @a = 3;

Query OK, 0 rows affected (0.00 sec)

mysql> SET @b = 4;

Query OK, 0 rows affected (0.00 sec)

mysql> EXECUTE stmt1 USING @a, @b;

+------------+

| hypotenuse |

+------------+

| 5 |

+------------+

1 row in set (0.00 sec)

mysql> DEALLOCATE PREPARE stmt1;

Query OK, 0 rows affected (0.00 sec)

首先我们先简单回顾下客户端使用 Prepare 请求过程:

客户端发起 Prepare 命令将带 “?” 参数占位符的 SQL 语句发送到数据库,成功后返回 stmtID。

具体执行 SQL 时,客户端使用之前返回的 stmtID,并带上请求参数发起 Execute 命令来执行 SQL。

不再需要 Prepare 的语句时,关闭 stmtID 对应的 Prepare 语句。

这里展示不使用 sql 预编译和使用 sql 预编译时的 Mysql 的日志。

2020-06-30T08:14:02.430089Z 10 Query COMMIT

2020-06-30T08:14:02.432995Z 10 Query select * from user where merchant_id='123456'

2020-06-30T08:15:10.581287Z 12 Query COMMIT

2020-06-30T08:15:10.584109Z 12 Prepare select * from user where merchant_id =?

2020-06-30T08:15:10.584725Z 12 Execute select * from user where merchant_id ='123456'

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/281958.shtml

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

相关文章

wav2midi 音乐旋律提取算法 附可执行demo

前面提及过,音频指纹算法的思路。 也梳理开源了两个比较经典的算法。 https://github.com/cpuimage/shazam https://github.com/cpuimage/AudioFingerprinter 后来一段时间,稍微看了下这两个算法,还有不少可以精简优化的空间。 例如抗噪&…

全新升级的AOP框架Dora.Interception[5]: 实现任意的拦截器注册方式

Dora.Interception提供了两种拦截器注册方式,一种是利用标注在目标类型、属性和方法上的InterceptorAttribute特性,另一种采用基于目标方法或者属性的调用表达式。通过提供的扩展点,我们可以任何我们希望的拦截器注册方式。目录一、IIntercep…

SCAU 算法课的题

8594 有重复元素的排列问题(优先做) 时间限制:1000MS 内存限制:1000K提交次数:1610 通过次数:656 题型: 编程题 语言: G;GCC;VC Description 设集合R{r1,r2,...,rn}是要进行排列的n个元素,其中r1,r2,...,rn可能相同。 试着设计一个算法&am…

react 数组新增_React 新特性 Hooks 讲解及实例(二)

本文是 React 新特性系列的第二篇,第一篇请点击这里:React 新特性讲解及实例什么是 HooksHook 是 React 16.8 的新增特性。它可以让你在不编写 类组件 的情况下使用 state以及其他的 React 特性。类组件的不足状态逻辑复用难缺少复用机制渲染属性和高阶组…

智课雅思词汇---二十二、-al即是名词性后缀又是形容词后缀

智课雅思词汇---二十二、-al即是名词性后缀又是形容词后缀 一、总结 一句话总结: 后缀:-al ②[名词后缀] 1、构成抽象名词,表示行为、状况、事情 refusal 拒绝 proposal 提议 withdrawal 撤退 1、名词性后缀acy是什么意思? 后缀&a…

javascript事件处理程序

javascript 事件处理程序 1、普通事件处理程序 <input type"button" value"click me" οnclick"showMessage()" /> function showMessage(){alert("clicked");} 2、DOMO 级事件处理程序 <span style"white-space:pre&…

eclipse新发现功能之dos和terminal(ssh连接)

dos功能&#xff1a; window——》show view——》other——》remote systems&#xff0c;选择remote shell&#xff0c;选择确定或者双击&#xff0c;打开了一个新工具窗口。点击remote shell窗口最右上角的小三角&#xff0c;在launch子菜单中选择local&#xff0c;点击即可。…

7天学会python_7天学会Python最佳可视化工具Seaborn(五):结构化展示多维数据

当探索具有中等数量(不多不少的意思……)维度的数据集时&#xff0c;一个很好的方式是基于不同的子数据集构建不同的实例&#xff0c;并将它们以网格的方式组织在一张图之中。这种技术有时被称为“lattice”或“trellis”(大概是格子图、网格图)&#xff0c;这跟“small multip…

面对峰值响应冲击,解决高并发的三大策略

2019独角兽企业重金招聘Python工程师标准>>> 当前在互联网的大潮下&#xff0c;众所周知淘宝、京东这些交易系统每天产生的数据量都是海量的&#xff0c;每天的交易并发也是惊人的&#xff0c;尤其是“双11”、“6.18”这些活动&#xff0c;对系统的峰值响应提出了非…

.NET 采用 SkiaSharp 生成二维码和图形验证码及图片进行指定区域截取方法实现

在最新版的 .NET 平台中&#xff0c;微软在逐步放弃 System.Drawing.Imaging &#xff0c;给出的理由如下&#xff1a;System.Drawing命名空间对某些操作系统和应用程序类型有一些限制。在Windows&#xff0c; System.Drawing 依赖于GDI操作系统附带的本机库。 某些Windows SKU…

Linux运维人员必会开源运维工具体系

新手必会用深&#xff08;8-15k&#xff09;标记&#xff0c;老鸟必会深浅蓝色(15-25K)标记操作系统&#xff1a;Centos,Ubuntu,Redhat,suse,Freebsd网站服务&#xff1a;nginx,apache,lighttpd,php,tomcat,resin数据 库&#xff1a;MySQL,MariaDB,PostgreSQLDB中间件&#x…

unity读取Text

sing UnityEngine;using System.Collections;using System.IO; //需要导入System.IO&#xff0c;主要使用它的File类public class TextTest : MonoBehaviour { private string Mytxt; //用来存放文本内容 void Start() { Mytxt ReadFile("C:\\Users\\Admin\\Desktop\\测试…

hibernate mysql 主从_MYSQL主从复制和写分离

基础篇https://edu.51cto.com/course/19845.htmlhttps://edu.51cto.com/course/19845.htmlhttps://edu.51cto.com/course/19841.htmlhttps://edu.51cto.com/course/21197.htmlhttps://edu.51cto.com/course/19886.htmlhttps://edu.51cto.com/course/19887.htmlhttps://edu.51ct…

深入剖析Redis系列(五) - Redis数据结构之字符串

前言 字符串类型 是 Redis 最基础的数据结构。字符串类型 的值实际可以是 字符串&#xff08;简单 和 复杂 的字符串&#xff0c;例如 JSON、XML&#xff09;、数字&#xff08;整数、浮点数&#xff09;&#xff0c;甚至是 二进制&#xff08;图片、音频、视频&#xff09;&am…

全新升级的AOP框架Dora.Interception[6]: 框架设计和实现原理

本系列前面的五篇文章主要介绍Dora.Interception的编程模式以及对它的扩展定制&#xff0c;现在我们来聊聊它的设计和实现原理。目录一、调用链抽象二、基于约定的拦截器定义三、基于调用上下文的依赖注入容器四、拦截器的提供五、调用链的构建六、方法拦截的实现原理七、依赖注…

activemq 安全连接

一、定义用户组1.1 simpleAuthenticationPlugin通过在activemq.xml中配置用户组<plugins> <simpleAuthenticationPlugin> <users> <authenticationUser username"admin" password"password" groups"admins,publishers,consumer…

React Native在Android当中实践(五)——常见问题

React Native在Android当中实践&#xff08;一&#xff09;——背景介绍 React Native在Android当中实践&#xff08;二&#xff09;——搭建开发环境 React Native在Android当中实践&#xff08;三&#xff09;——集成到Android项目当中 React Native在Android当中实践&#…

完成登录与注册页面的前端

完成登录与注册页面的HTMLCSSJS&#xff0c;其中的输入项检查包括&#xff1a; 用户名6-12位 首字母不能是数字 只能包含字母和数字 密码6-12位 注册页两次密码是否一致 JS&#xff1a; function fnLogin() {var uSer document.getElementById("user");var pAss do…

mysql505复位密码_mysql5 如何复位根用户密码[官方文档]

如何复位根用户密码如果你从未为MySQL设置根用户密码&#xff0c;服务器在以根用户身份进行连接时不需要密码。但是&#xff0c;建议你为每个账户设置密码如果你以前设置了根用户密码&#xff0c;但却忘记了该密码&#xff0c;可设置新的密码。下述步骤是针对Windows平台的。在…

WPF效果第二百零一篇之实现合并单元格

早一段时间又一次出差青海省西宁市;回来又是总结又是各种琐事,也没顾得上去分享点东西;大周末的就在家分享一下,这二天再次基于ListBox实现的合并单元格的效果:1、ListBox嵌套ListBox的前台布局:<ListBox ItemsSource"{Binding LCPListData}" x:Name"Manufac…