Skip to content

Latest commit

 

History

History
188 lines (124 loc) · 4.98 KB

File metadata and controls

188 lines (124 loc) · 4.98 KB

大家应该都听说过SQL注入吧,但是,网络上的例子貌似都是一些代码片段,如果一个新手想要自己尝试一下SQL注入来直观的感受一下SQL注入的危害,显得很无助。我刚学习这方面知识的时候也苦苦找不到这样的代码。最近在知乎上看到很多人都提关于SQL注入的问题,于是,打算写一篇这样的博客。

直接上代码:

先创建数据表:

CREATE TABLE IF NOT EXISTS `users`(
   `id` INT UNSIGNED AUTO_INCREMENT,
   `username` varchar(200) NOT NULL,
   `password` CHAR(32) NOT NULL,
   PRIMARY KEY ( `id` )
)ENGINE = InnoDB DEFAULT CHARSET = utf8;

INSERT INTO `users` (`id`, `username`, `password`) VALUES
(1, 'admin', MD5('admin')),
(2, 'huanghantao', MD5('huanghantao'));

下面是结果:

(密码是结果md5函数加密的)

然后是PHP脚本处理登录逻辑的代码:

<?php
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "test";
 
// 创建连接
$conn = new mysqli($servername, $username, $password, $dbname);
 
// 检测连接
if ($conn->connect_error) {
    die("连接失败: " . $conn->connect_error);
}

$username = "admin";
$password = "admin";
$sql = "SELECT * FROM users where username = '" . $username . "' AND password = '" . md5($password) . "'";
$result_obj = $conn->query($sql);

if ($result_obj->num_rows) {
	while($row = $result_obj->fetch_assoc()) {
		var_dump($row);
    }
}

OK,程序大概就是这样了,

现在我们执行上面这段PHP脚本:

嗯,符合我们的预期。(因为用户名和密码都正确,所以打印出了用户的结果)

好的,接下来开始我们的表演:

我们修改一下PHP脚本的username变量:

$username = "admin' --";
$password = "密码随便写"; // 没错,你写中文也行

完整代码如下:

<?php
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "test";
 
// 创建连接
$conn = new mysqli($servername, $username, $password, $dbname);
 
// 检测连接
if ($conn->connect_error) {
    die("连接失败: " . $conn->connect_error);
}

$username = "admin' --";
$password = "代码随便写";
$sql = "SELECT * FROM users where username = '" . $username . "' AND password = '" . md5($password) . "'";
$result_obj = $conn->query($sql);

if ($result_obj->num_rows) {
	while($row = $result_obj->fetch_assoc()) {
		var_dump($row);
    }
}

我们执行代码:

说的是$result_obj变量不是一个对象,所以没有属性。好的,我们打印一下$result_obj看看它究竟是什么:

var_dump($result_obj);

原来返回的是一个boolean类型的变量。说明我们的SQL语句没有执行成功。这就是很坑的一个地方了,网络上的文章大多数是草草的告诉我们,在表单填写类似这样的东西就可以了:

admin' --

即加个单引号 ',加两个 -。实际上,或许你得再加点东西。

我们修改下代码:

$username = "admin' -- // ";
$password = "代码随便写";

也就是说再加两个/

好的,我们执行一下代码:

怎么样,就算我们不知道密码,只要我们知道这个用户的用户名,就可以登录到这个用户的页面对吧。

好的,接下来,我们再试试,即使没有用户名和密码,我们也可以得到所有用户的用户名和密码:

$username = "' or 1 -- // ";
$password = "代码随便写";

执行后的结果:

很可怕对吧。

至于这两段代码中的:

admin' --
和
' or 1 --

什么意思,网上的文章已经讲烂了,就不多说了。

通过什么的操作,我们可以发现,那个单引号'特别捣蛋对吧,所以,我们修改下代码,对单引号进行转义:

$username = "' or 1 -- // ";
$username = addslashes($username);
$password = "代码随便写";

执行后的结果:

可以看到,并没有打印出用户信息,所以这个函数阻挡了此次攻击。原因如下:

or前面的单引号被转义了。

但是,并不建议通过addslashes对单引号转义的方式来阻挡这种类型的SQL注入。因为addslashes对有些特殊字符后跟上'(单引号)并不会加把这个'变成/'

这也是为什么很多人建议使用PDO来对数据库进行操作的原因了。

好的,文章到这里结束了,希望对大家有所帮助。文中的代码都可以复制后直接使用,希望可以减少大家踩坑的时间。

happy ending…...