为什么会出现sql注入?究竟什么是sql注入?让我们来看一个简单的例子
$username = $_POST['username']; //获取用户提交的用户名 $password = md5($_POST['password']); //获取用户提交的密码,并且进行哈希处理 $user = $db->query("SELECT * FROM account WHERE username='$username' and password='$password'"); if (empty($user)) { exit('user not exists or wrong password'); } else { //login success } |
上面是一个很普通的登录相关的代码,看上去为了避免像CSDN明文密码那样子的惨剧再次上演,程序员还贴心地对密码做了一次哈希。如果一切正常,比如用户填写的用户名是admin,密码是123456,那么我们拼接后提交给数据库的sql应该就是
SELECT * FROM account WHERE username='admin' AND password='e10adc3949ba59abbe56e057f20f883e' |
看上去非常正常,和我们想要的完全一样。可是,如果用户提交的用户名不是『admin』,而是『admin’– 』,那么会发生什么呢?让我们再拼接一次sql试试看。
SELECT * FROM account WHERE username='admin'-- ' and password='e10adc3949ba59abbe56e057f20f883e' |
从高亮来看似乎出了点问题。为什么?『– 』在很多数据库中都代表这注释(注意最后有一个空格),要知道数据库是不会去区分一条sql语句里哪部分是你自己编码的,哪部分是用户提交的,对它来说,你最后给它的一定是一个字符串。根据上面这个字符串,数据库忠实地返回了那个叫admin的用户的信息,因此入侵者成功地绕过了我们的限制,登入了系统QAQ
其实上面说到的最后给数据库的一定是一个字符串,这并不完全正确,因为有预处理语句的存在,具体的知识我们会在后面谈防御sql注入的时候介绍
什么?你说你很机智的用户名不叫admin而是叫xiami,所以完全没有关系?那你有没有思考过如果用户提交的用户名是『’ or 1=1– 』怎么办(→_→)
嗯,是不是觉得上面的例子太低级了?但在大概01年左右,基本上所有带登录功能的系统,似乎都存在着这个问题。。。
sql注入除了可以绕过登录,在更多的时候是用来获取信息(比如用户的用户名密码、个人隐私信息等),为后续的渗透做铺垫,那么这又是如何做到的呢?再来举个栗子
$post_id = $_GET['id'];
$post = $db->query("SELECT title, author, content FROM posts WHERE id=$post_id");
//将$post内容展示在页面上
有了上面的铺垫,我们可以猜到这儿的$post_id肯定不会乖乖的是一些数字了,那可以传一些什么呢?我们来试试看获取用户的账号吧。提交『-1 UNION SELECT username, password FROM account』试试看
SELECT title, content FROM posts WHERE id=-1 UNION SELECT username, password FROM account |
这儿的-1只是为了确保找不到这么一篇文章。因为如果填写一篇存在的文章的id,那么我们后面union出来的结果就无法展示出来了(因为文章详情页基本上只会取第一行的结果进行展示)
如果这儿没看懂,没关系,因为接下来我们会针对每一种sql注入一个个进行分析和介绍。