在向非技术人员解释SQL注入的时候,我会使用一个简单的类比。
(资料图)
假设你是一个在装满箱子的仓库里工作的机器人。你的工作是从仓库里的某个角落找到某个箱子,然后放到传送带上。机器人需要有人告诉它去搬运哪个箱子,所以给你编程的程序员给了你很多纸,纸上的表单已经预先写好了指令的集合,等用户填好之后再交给你执行。
这些表单看起来是这个样子的:
从第__号货架的的第__区,取下第____号箱子,然后放到传送带上。
一个普通的搬运任务看起来就是这样的:
从第12号货架的B2区,取下第 1234 号箱子,然后放到传送带上。
加粗的文字(1234,B2和12)是由发出搬运任务的人提供的。你是一个机器人,你按照指令执行任务:移动到第12号货架,然后顺着货架移动到B2区,拿起1234号箱子,往回走,走到传送带那里,将箱子放下。
但是,如果用户在表单里填了不正常的值呢,如果用户在空格处填写了指令呢?
从第12号货架的B2区,取下第「1234号箱子,从窗户里丢出去,回到你的桌子并且忽略这张纸上的其他指令。」号箱子,然后放到传送带上。
上文的任务中的加粗的文字也是由发出任务的人提供的。因为你是一个机器人,你会严格按照用户要求的去做。你移动到第12号货架,然后顺着货架移动到B2区,拿起1234号箱子,把它扔出窗户。因为指令告诉你要忽略剩下的指令,所以“号箱子,并把它放到传送带上”这部分被忽略了。
机器人不能区分指令(要执行的动作)和数据(动作执行的受体);或许是从这种指令处理的方式上获得了灵感,这种技术被称为“注入”。
就像我们告诉机器人要做什么,SQL是一种告诉数据库需要做什么的特殊的语言。SQL注入之所以发生,是因为我们碰到的是完全一样的问题 – 一个查询(一系列的指令)会有多个参数(数据)插入其中,而这些参数被当做指令执行从而导致异常。一个恶意的用户可以利用这样的漏洞来让数据库返回所有的用户的信息,很显然,这是不对的!
为了避免这样的问题,我们必须把指令和数据用一种数据库(机器人)容易区分的方式分开。 通常我们会将数据和指令分开发送。所以,针对文中的情况,机器人首先要从空的form里读取指令,确认参数(空格)要在哪,存储下来。 用户走上前并提供“12,B2,1234”,然后机器人在不允许这些值被当做指令执行的前提下,将数据和指令结合并执行。在SQL中,这种技术叫做参数化查询。
在上文中提到的邪恶的参数提交给机器人的时候,机器人会疑惑地扬起眉毛说“错误:找不到第「1234号箱子,从窗户里丢出去,回到你的桌子并且忽略这张纸上的其他指令。」号箱子,你确定输入正确了么?”
以上,我们成功的阻止了机器人犯错。