xiaohanliang
Database
Database
  • review
  • MySQL
    • 0. 索引就是树吗
    • 1. 索引是怎么发挥作用的
    • 2. 聊聊怎么估时间
    • 3. 主键玄学
    • 4. 事务的执行过程@ACD
    • 5. MVCC就是用undolog回退
    • 6. 事务如何彼此隔离@I
    • 7. 如何人为的制造死锁
    • 8. 引擎是干什么的
    • 9. 主从复制怎么做到的
    • 10. 寻找同步起始点GTID
    • 11. 预解析Statement
  • Redis
    • 0. Hash@数据结构
    • 1. ZSet@数据结构
    • 2. 场景与玩法@数据结构
    • 3. 可能的风险点
    • 4. Redis的落盘
    • 5. 关于效率的讨论
    • 6. 主从模式@集群化
    • 7. [WIP]Proxy实现@集群化
    • 8. 标准玩法@集群化
  • KV/Distributed
    • 0. 面临的问题
    • 1.Raft@原理
    • 2. LSM@原理
    • 3. [WIP]分布式事务@原理
Powered by GitBook
On this page
  • Introduction
  • SQL语句解析
  • 预解析为什么防范注入
  • 看看b(指包,抓包看看)
  • Statement一定比直接查询要好吗?

Was this helpful?

  1. MySQL

11. 预解析Statement

Introduction

在看一个注入错误的时候发现有一招叫Statement, 想起来当时看驱动的时候也总是看到stmt字样, 看多了觉得鬼畜, 老样子从场景入手, 现在假设你想查: select * from users where id = 5, 那么在你的程序里你就会这么写:

db.Query("select * from users where id = ?", 5)

过两天安全部找你, 说这里有注入风险, 让你给修一下, 你看了一下决定过段时间再说, 3个月过去了安全工单还在那里(

SQL语句解析

Statement中文翻译叫"参数化查询", 烂翻译(不意外), 我叫它"预解析", 我们都知道SQL语句到达MySQL服务器经过的第一层是语句解析, 任何语句都需要经过语义解析才能开始被执行, 一条语句会被拆成很多很多个小块, 每个小块都有一个自己的含义, 比如你想要执行的动作, 想要查询的表/库, 想要的字段.

比如在我们上面的例子中你想要执行的动作就是SELECT, 你想要查询的表是users, 筛选条件是id=5, 就这么些小块, 拆好了以后这些小块最终会被送给引擎层, 去磁盘里查你想要的数据.

预解析为什么防范注入

所谓预解析, 就是select * from users where id=?这个语句解析后产生的小块, 经过预解析后的语句, 明确要求, 这里应该是一个数字, 表示id. 而SQL注入呢? 会填进来一个超级复杂的语句, 根本不符合解析过的语句要求, 自然是报错的.

这种行为很像一个"模板", 一个模板要求你这里只能填数字, 你填写一个复杂语句并不符合模板要求, 虽然注入语句整体是通顺的, 但并不符合模板要求

看看b(指包,抓包看看)

模板生成过程

stmt, err := db.Prepare(
    "select * from test.users where id = ?",
)

这条语句执行以下会让MySQL服务器做以下事情: 帮我预解析一下这个模板, 然后服务器收到了以后会生成一个StatementID

模板使用过程

stmt.Query(225)

然后你通过这条语句, 开始利用刚刚定义出的模板, 传递一个参数225, 告诉MySQL服务器, 我要使用刚刚的模板, 这里的参数是225

Statement一定比直接查询要好吗?

你也看见了如果使用模板查询, 第一步是先生成模板, 然后使用模板, 最后还要关闭模板, 回收这个ID, 比较麻烦

除此之外Statement有一种问题叫reprepare问题, 就是你使用stmt的链接对象, 跟你创建的链接对象必须是同一条链接对象. 怎么说呢? 你知道你的go-sql-driver会为你维护一个连接池,

你通过连接对象-A创建了stmt, 稍后你想要使用这个链接对象的时候, 我们必须再把A找回来, 如果A忙, 那就要重新创建一遍, 加大成本, 叫reprepare.

因此只在面临用户输入参数的时候使用Statment就好了, 剩余的时候不用这么麻烦的

Previous10. 寻找同步起始点GTIDNext0. Hash@数据结构

Last updated 4 years ago

Was this helpful?