2021.07.18 技術シェア
【技术浅谈】骇客攻防 — SQL注入

前言


SQL注入(SQL Injection)是一种利用编程语言漏洞攻击网站的方法,虽然该方法早已过时,但仍对一些网站有效果。


图片


 

SQL语言简介


Sequel或者叫SQL是一种用来和数据库(Database)沟通的编程语言。它的语法一点都不复杂,也不必须要写像其他编程语言如C和Java里面的大括号或者是分号之类的符号。它其实很像英语,你甚至可以编写"Select from this table"。用类似英语的一些命令就可以从数据库中获得想要的结果。


 

SQL语言简介


这个语言已经有很多年的历史了,一切都风平浪静,直到互联网的出现。从最初的万维网到现在,网络实现的最基本的功能一直没有变,当我们打开浏览器,我们向远端的服务器发送请求,这个请求可以是“我要看这个网页”,然后远端的服务器将这个网页通过互联网发送到我们的浏览器上显示给我们,这就是一个简单的打开网页操作。几乎所有的网站交互操作都可以总结为:我向远端服务器发送一个内容,远端服务器根据我发送的内容从数据库中获取不同的内容,并返回给我。


 

SQL注入


早期的一些用来接收用户发送的请求的一些编程语言没有以一种明智的方式的处理用户发送的内容,这其中最著名的就是早期的PHP语言。


假设下面的登录表单的后端使用PHP语言接收Username和Password,然后将接收到的内容直接传给SQL语言进行数据库间的交互。


图片


为了减少PHP语言对大家的困扰,我们就省去PHP这个中介,用户填写这个表单的操作就可以理解为直接完善SQL语言的代码,这行代码写为<Select user from Users where username = "Gilfoyle";>。这行代码可以翻译为“从Users表中找username为Gilfoyle的user”。然后只要我输入正确的密码,数据库将发回有关Gilfoyle用户的所有详细信息。


图片


到目前为止一切正常,看起来没有什么问题。但是要注意的是Gilfoyle两边的双引号,我输入Gilfoyle,后端会自动在我输入的内容外面加上双引号。好的,如果现在我要输入Gilfoyle加上一个引号呢(即输入<Gilfoyle">)?


图片


这个时候SQL语句就会自动写成<Select user from Users where username = "Gilfoyle"">。因为三个双引号的同时出现在很多语言里是一种编译错误,因此这里会向用户返回一个错误提示。这种错误很令人厌烦,因为如果我们输入的内容里经常会出现双引号,就会经常导致这样的错误发生。


 


更严重的问题是我们可以通过这种方式造成更大的损害,因为SQL语言不光只有Select命令,它还有Insert命令,用来向数据库中添加内容,它还有Update命令来更改内容,然后,它还有Delect,删除内容。所以如果我输入的不只是加了一个引号这么简单,而是输入了<Gilfoyle";>,然后在后面加上一条别的命令,比如删除所有内容,它是会被正常运行的。


图片


点击Submit,它将转换为简单的SQL命令,然后发送到数据库,数据库会理解分号右边有一个新的命令,这个命令让它删除所有内容。


这个漏洞的核心是存在像引号这样的危险字符,填补这个漏洞的方法之一则是使用转义字符,即反斜杠。程序员可以在程序里定义一个转义函数,每次接收到用户的输入,都调用该函数将输入中出现的引号前面都加一个反斜杠,这样引号则会被数据库当作文本中的引号进行对待,不会有什么特殊反应。


这种方法是有效的,但是很笨拙,因为类似的SQL注入方式还有很多,即使用这种解决办法解决了一种注入,还会不断有新的注入出现,这就会对软件更新带来巨大的工作量。在网上搜索‘SQL injection example’,你会看到各种奇葩的注入语句,防不胜防。


 

如何解决


一个经典的解决方法叫做Prepared Statement,这个方法的原理是将用户输入的内容不直接的放进SQL语句中给数据库运行,而是将内容和SQL的运行进行分离,先在数据库中运行好一段SQL代码比如<SELECT * FROM users WHERE user = ? AND password = ?>,数据库看到这个问号,会理解为“这个问号的地方就是我之后要接收的字段信息,而不是任何的命令,不是删除命令,也不是插入命令,不要对这里做任何事情”,这样,用户即使输入了注入攻击,也不会对数据库产生任何的迷惑性行为了。


当然,这里只是对一个简单的例子的傻瓜式描述,这个方法要更复杂一些,如果你是网络程序员,你应该查阅有关措施的最新安全准则。但是你绝对应该对这个漏洞提高警惕,做好防范措施,如果你使用的编程语言,或者你做的网站没有使用Prepared Statement,那么就会很容易受到攻击,所以你需要解决这个问题。但是与此同时,随着骇客的不断进化,还会有更糟糕的情况等着你。


 


图片