Pinkie,感谢您发布代码。
$sql = 'SELECT a.videote as videote, b.user_name as user_name'.
' FROM '.$video.' as a,'.$users.' as b'.
' where b.user_name=$_GET['user'] and... //if i replace $_GET['user'] with john then it works
这里有一些问题,但我们可以解决它们。
更改字符串时会出现语法错误。您对$video 和$users 的方式有正确的想法。但是当添加$_GET['user'] 时,PHP 认为第一个撇号正在结束当前字符串。
考虑一下:
' where b.user_name=$_GET['user'] and...'
看起来像两个字符串,由单词“user”分隔:
' where b.user_name=$_GET[' user '] and...'
这不是正确的语法,因此返回 500 错误。我猜如果您尝试一下,您的错误就会消失:
' where b.user_name=' . $_GET['user'] . ' and...'
下一个问题是,如果用户要为“user”参数发送精心设计的值,他们可能会导致查询以您不希望的方式运行。
试试这个:创建一个名为 login.php 的文件,其内容如下:
<?php
// Just display the output; no HTML formatting needed
header("Content-Type: text/plain");
// This must succeed, or mysql_real_escape_string() won't have any effect
mysql_connect('mysql_host', 'mysql_user', 'mysql_password')
OR die(mysql_error());
$safeQuery = 'SELECT count(*) FROM users WHERE user=\'' . mysql_real_escape_string($_GET['username']) . '\' AND pass=\'' . mysql_real_escape_string($_GET['password']) . '\';';
echo " safeQuery is: $safeQuery\n";
$unsafeQuery = 'SELECT count(*) FROM users WHERE user=\'' . $_GET['username'] . '\' AND pass=\'' . $_GET['password'] . '\';';
echo "unsafeQuery is: $unsafeQuery\n";
?>
加载login.php?username=bob&password=sample。输出看起来很合理:
safeQuery is: SELECT count(*) FROM users WHERE user='bob' AND pass='sample';
unsafeQuery is: SELECT count(*) FROM users WHERE user='bob' AND pass='sample';
现在尝试加载login.php?username=bob&password=sample' OR 'hello'='hello":
safeQuery is: SELECT count(*) FROM users WHERE user='bob' AND pass='sample\' OR \'hello\'=\'hello';
unsafeQuery is: SELECT count(*) FROM users WHERE user='bob' AND pass='sample' OR 'hello'='hello';
安全查询将返回零,除非您有一个名为 bob 的用户,其密码确实是 sample' OR 'hello'='hello"。
但是,不安全的版本将返回数据库中的用户总数。 WHERE 子句现在是:
WHERE user='bob' AND pass='sample' OR 'hello'='hello'
OR 'hello'='hello' 将使条件在所有情况下都为真,即使bob 不存在或密码不是sample。
您的部分查询甚至可以被注释掉。试试login.php?username=bob' --:
safeQuery is: SELECT count(*) FROM users WHERE user='bob\' --' AND pass='';
unsafeQuery is: SELECT count(*) FROM users WHERE user='bob' --' AND pass='';
密码参数现在被忽略,因为它嵌入在 SQL 注释中。
因此,即使您只是执行一个 SELECT 语句,如果他们的输入没有被转义,聪明的用户也可以操纵结果。
您可以使用 mysql_real_escape_string 来防止此类错误值。此函数将在必要时添加反斜杠,以防止输入数据作为 SQL 执行。
$sql = 'SELECT a.videote as videote, b.user_name as user_name'.
' FROM '.$video.' as a,'.$users.' as b'.
' where b.user_name=\'' . mysql_real_escape_string($_GET['user']) . '\' and...';
php.net page for mysql_real_escape_string 中的示例 1 有一个使用 sprintf 的绝佳示例:
$query = sprintf("SELECT * FROM users WHERE user='%s' AND password='%s'",
mysql_real_escape_string($user),
mysql_real_escape_string($password));
每个%s 都被参数替换(按照它们指定的顺序)。这样可以更轻松地保持查询的可读性,同时防止错误的输入数据。