基于php+mysql的sql注入攻守实操

基于php+mysql的sql注入攻防实操

摘要:
基于php+mysql平台的sql注入攻防的实操,提供较详细的ubuntu平台上的操作步骤,方便练手。

使用的平台:

Ubuntu 12.04,php 5.3.10, mysql Ver 14.14, Apache/2.2.22

步骤:
1. 在ubuntu上安装Apache,mysql,具体过程自行百度;
2.1 首先熟悉如何再mysql中建立数据表?包括用户名和对应的密码;并且熟悉其中的查询命令;完成查询测试;
2.2 完成php端的代码,完成php和mysql的链接;完成链接查询测试;
2.3 基于浏览器端的sql攻击测试;

2.1首先是对mysql的操作:
a)创建user数据库:create database user;
b)切换到user数据库:use user;
c)创建account表:create table account(name VARCHAR(20), password VARCHAR(20));里面包含用户的名字和密码;
d)在account表中插入数据:
insert into account values
     ('aaa', '111'),
     ('bbb', '222');
即完成在数据库user的account表中插入两个用户的用户名和密码;

2.2 如何将php与mysql相联接?
mysql端需要设置权限,将user数据库的访问权授予findme,并且密码为findmeifyoucan.
grant select, delete on user.*  to findme identified by 'findmeifyoucan';
在php后端需要建立链接的代码如下:
$db = new mysqli('localhost', 'findme', 'findmeifyoucan', 'user);


2.3下面分别是浏览器端和php后端的对应的代码(显示原理为主,代码尽量简化);浏览器端的html代码login.html:

<html>
<head>
<title>Please log in.</title>
</head>

<body>

<form action="result.php" method="post">
	Enter your user name:<br />
	<input name="user" type="text" size="40" />
	<br />
	Enter your password:<br />
	<input name="psd" type="text" size="40" />
	<br />
	<input type="submit" name="submit"  value="search" />
</form>

</body>

</html>

下面是php端的代码result.php:
<span style="font-size:14px;"><html>
<head>
<title>see if you can login</title>
</head>

<body>
<h1>Check wether you can login in or not?</h1>

<?php
function check($db)
{
	$name = $_POST["user"];
	$password = $_POST["psd"];
	
	$result = $db->query("select count(*) from account where name = '$name' and password = '$password'");
	$row = $result->fetch_assoc();

	if($row['count(*)'] != 0){
		echo 'you login in';
	}else{
		echo 'you not login';
	}
}

$db = new mysqli('localhost', 'findme', 'findmeifyoucan', 'user');

if(mysqli_connect_errno()){
	echo 'Error: could not connect to database user. Please try again.';
	exit;
}

check($db);
$db->close();

?>

</body>
</html></span>
在浏览器中,访问localhost/login.html,再输入登陆的用户名和密码即进行测试。上面的代码不能抵御下面sql注入攻击:
如果输入user:aaa, password:111;则顺利登陆;这不奇怪,但是在password处输入下面的代码:112' or '1'='1, 也可以正常登陆,此时的sql语句如下:
select count(*) from account where name='aaa' and password='112' or '1'='1';
后面的'1'='1'逻辑成立,所以返回不为0。

那怎么应对这种情况呢?常见的解决方式是对输入的值进行转义符操作;具体的操作方式如下:
$name=addslashes($name);
$password=addslash3s($password);
这样的操作后,就可以规避112' or '1'='1的攻击;原因也很简单,因为select查询语句变为如下:
select count(*) from account where name='aaa' and password='112\' or \'1\'=\'1';
数据库中用户'aaa'的密码明显不可能是'112\'而且\'1\'=\'1'也不成立,所以就起到防御作用。

结论:
1. 上述代码虽然简单,但是本人也不是一次就写对,还是借助了php的调试功能,需要区分php在开发和
生产阶段的调试设置的不同;
2. 实践过程再一次证明:只要系统可观察,就可以理解;