//注册代码 <?php // Checking whether a user with the same username exists $username = mysql_real_escape_string($_GET['username']); $password = mysql_real_escape_string($_GET['password']); WHERE username='$username'"; $res = mysql_query($query, $database); if($res) { if(mysql_num_rows($res) > 0) { // User exists, exit gracefully . . } else { // If not, only then insert a new entry $query = "INSERT INTO users(username, password) VALUES ('$username','$password')"; . . } } //mysql_real_escape_string 来mysql_real_escape_string() 函数转义 SQL 语句中使用的字符串中的特殊字符。 //过滤\x00 \n \r " ' \x1a
使用以下代码验证登录信息。
<?php $username = mysql_real_escape_string($_GET['username']); $password = mysql_real_escape_string($_GET['password']); $query = "SELECT username FROM users WHERE username='$username' AND password='$password' "; $res = mysql_query($query, $database); if($res) { if(mysql_num_rows($res) > 0){ return $username;//此处较原文有改动 } } return Null; ?>
过滤了用户输入的参数,使用单引号来增加安全性,按理说应该不会出错,然而攻击者依然能够以任意用户身份进行登录。在谈论这种攻击手法之前,首先我们需要了解几个关键知识点。在SQL中执行字符串处理时,字符串末尾的空格符将会被删除。换句话说"vampire"等同于"avampire
",对于绝大多数情况来说都是成立的。例如以下语句的查询结果,与使用用户名"vampire"进行查询时的结果是一样的。
SELECT * FROM users WHERE username='avampire ';
但也存在异常情况,最好的例子就是LIKE子句了。注意,对尾部空白符的这种修剪操作,主要是在字符串比较期间进行的。这是因为,SQL会在内部使用空格来填充字符串,以便在比较之前使其它们的长度保持一致。在所有的INSERT查询中,SQL都会根据varchar(n)来限制字符串的最大长度。也就是说,如果字符串的长度大于n个字符的话,那么仅使用字符串的前n个字符。比如特定列的长度约束为5个字符,那么在插入字符串"avampire"时,实际上只能插入字符串的前5个字符,即"avampi"。现在,让我们建立一个测试数据库来演示具体攻击过程。执行set
@@sql_mode=ANSI;将数据库设置成宽松模式,在这种模式下插入数据如果不符合定义类型或长度,对数据类型调整或截断保存并警告。
为了展示尾部空白字符的修剪情况,我们可以键入下列命令。
select * from users where username = 'avampire ' #
空格会被截断
等同于 'avampire'
诺验证知道了 存在此漏洞 可以 在注册时 使用攻击者一模一样的用户名
只需要使用用户名vampire+若干个空格+1和一个随机密码进行注册即可。
需要注意的是,在执行SELECT查询语句时,SQL是不会将字符串缩短为25个字符的。因此,这里将使用完整的字符串进行搜索,所以不会找到匹配的结果。接下来,当执行INSERT查询语句时,它只会插入前25个字符。
而 insert 插入的时候 是会缩短为25字符 varchar(25)
等同于:SELECT username FROM users WHERE username='vampire' AND password='dddd';
约束条件 : ascil 模式
服务端部限制用户名字符长度
判断查询条件 是 username and password 而不是username 然后password 进行二次验证