//连接数据库
$coon = mysql_connect('localhost','root','root') or die('Connect Error '.mysql_error());
mysql_select_db('sqlinjection',$coon) or die('Datebase Error '.mysql_error());
//构造查询语句
$query="SELECT * FROM user WHERE username='".$_GET["username"]."' AND password='".$_GET["password"]."'";
echo $query."<br/>";
//执行sql语句
$result= mysql_query($query);
//echo $result;
//判断返回数据的数目
$rowcount=mysql_num_rows($result);
//判断 如果数量大于1标示登录成功
//echo $rowcount;
if($rowcount!=0){
echo "OK";
}else{
echo "ERROR";
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>SQL injection test</title>
</head>
<body>
<form class="" action="test.php" method="GET">
<input type="test" name="username" value=""><br/>
<input type="password" name="password" value=""><br/>
<input type="submit" name="sub" value="Login">
</form>
</body>
</html>
首先我们先看一下测试代码,首先可以看到的是参数并没有进行相关的过滤,肯定会产生注入,但是今天我们讨论的是万能密码的问题。
关于万能密码我们应该都知道,常见的万能密码包括:
1:"or "a"="a
2: ')or('a'='a
3:or 1=1--
4:'or 1=1--
5:a'or' 1=1--
6:"or 1=1--
7:'or'a'='a
8:"or"="a'='a
9:'or''='
10:'or'='or'
11:1 or '1'='1'=1
12:1 or '1'='1' or 1=1
13: 'OR 1=1%00
通过我们的测试代码可以发现,开发在验证登录的时候,只是将用户输入作为查询条件进行查询,然后mysql_num_rows函数进行判断返回数据的数量,如果返回的数量大于1证明数据库中存在该用户,然后允许登录,正常情况下执行的SQL语句为:
[AppleScript] 纯文本查看 复制代码
1 |
|
但是当我们提交 【' or '1'='1】时,由于程序并没有对特殊字符进行过滤,将用户输入的直接带入查询,最后执行的SQL语句为:
[AppleScript] 纯文本查看 复制代码
1 |
扫描二维码关注公众号,回复:
13060400 查看本文章
|
这样SQL返回的值始终为1,就成功绕过了程序的验证。
关于修复:
[PHP] 纯文本查看 复制代码
1 2 3 4 5 6 7 8 9 |
|
以上代码对返回的数据与用户输入数据进行了比较验证,避免了万能密码的产生。
先看一段存在sql注入的代码:
[PHP] 纯文本查看 复制代码
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
|
参数没有进行任何过滤 而且查询后没有对数据进行验证,看到这我们应该想到万能密码(http://bbs.ichunqiu.com/thread-10851-1-1.html)
正常的查询如图
我们用万能密码尝试登录,我们可以看到红线之后的所有数据已经被注释掉,只有之前的语句被mysql所执行,同时后边的and 1=1返回永远为1,从而造成万能密码
下面看一下我们修改为预置参数查询后的代码:
[PHP] 纯文本查看 复制代码
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
|
我们正常登录
我们看一下执行的语句(mysql日志)
我们再试一下万能密码 发现登录并没有成功
我们再看一下执行的语句
我们将将16进制转换一下
--------
我们将参数化查询与普通的查询对比一下
可以看到 参数化查询在真正执行之前会进行数据库预编译 放在缓存里面,当运行时动态地参数传递,即使参数里有敏感字符 数据库也会作为一个参数一个字段的属性值来处理而不会作为一个SQL指令。