我的PHP应用程序有一个查询,它使用md5哈希作为输入,从用户通过GET方法,然后它将$mysqli->real_escape_string()
应用于它。之后它运行SELECT语句。
这个功能有多安全?是否有可能SQL注入它或XSS呢?
答案 0 :(得分:1)
这是安全的。如果你感觉不安全,它只有字符和整数,你可以很容易地测试它是一个md5字符串(见下面的例子)。但同样,并不需要所有这些。
另一种选择是prepared statements。他们有点复杂但安全:
$stmt = $mysqli->prepare("INSERT INTO test(id) VALUES (?)");
$stmt->bind_param("s", 'a1b2c3'); // s stands for String, i would be Integer
$stmt->execute();
这是一个非常简单的例子,代码块上方的url解释得更多。请记住,准备好的声明有一个开销!对每个查询执行1次执行此操作会降低速度。
检查字符串是否为md5哈希的小例子:
function isMd5($string){
/// md5 strings are 32chars* long. Simple test, do that first:
if( strlen($string)!==32){ return false; }
// It only has chars (A-F) and integers, if any other character->not md5
elseif( preg_match("^[0-9a-f]", $string) ){ return false; }
// No errors, return true:
return true;
}
// *rawmode ha 16 chars, but when you work with that, you'll know
这不是一个非常有用的功能,因为它不会真正保证很多,这只是为了向您展示如何验证信息。您阅读文档以查看结果,并进行检查以测试它是否与可能的结果相匹配。
答案 1 :(得分:1)
安全。但是如果你想要更安全,那么你可以使用预备语句,这是使用任何方程创建查询的最安全的方法,而不仅仅是MD5:http://php.net/manual/en/mysqli.prepare.php
答案 2 :(得分:0)
TL; DR
不,它总是安全。
安全使用需要您......
...仅使用它来转义SQL string literals。
如果对任何其他SQL令牌使用不受信任的数据,则必须以其他方式防止SQL注入。一些微不足道的例子:
尝试用于转义其他文字,例如整数:
# use as /script.php?id=0+OR+1
$id = $mysqli->real_escape_string($_GET['id']);
$mysqli->query("SELECT * FROM `users` WHERE `id` = $id")
这将提交:
SELECT * FROM `users` WHERE `id` = 0 OR 1
尝试用于转义对象标识符,例如列名:
# use as /script.php?col=id%60+%3D+0+OR+1+--+
$col = $mysqli->real_escape_string($_GET['col']);
$mysqli->query("SELECT * FROM `users` WHERE `$col` = 123")
这将提交:
SELECT * FROM `users` WHERE `id` = 0 OR 1 -- ` = 123
尝试用于转义SQL:
# use as /script.php?orderby=OR+1
$orderby = $mysqli->real_escape_string($_GET['orderby']);
$mysqli->query("SELECT * WHERE `id` = 0 $orderby")
这将提交:
SELECT * FROM `users` WHERE `id` = 0 OR 1
...正确引用这些转义字符串文字。
有两种可能的方法。之一:
引用带有单引号'
字符的转义字符串文字;或
明确设置SQL mode,其中既不包含ANSI_QUOTES
也不包含NO_BACKSLASH_ESCAPES
,然后引用转义的字符串文字双引号"
字符。
如果您没有完全执行这两个步骤之一,您仍然可能容易受到SQL注入攻击。例如,如果服务器默认设置NO_BACKSLASH_ESCAPES
,并且您没有明确更改该模式:
# use as /script.php?name=%22+OR+1+--+
$name = $mysqli->real_escape_string($_GET['name']);
$mysqli->query('SELECT * FROM `users` WHERE `name` = "'.$name.'"');
这将提交
SELECT * FROM `users` WHERE `name` = "" OR 1 -- "
...仅在首次设置the encoding of your database connection后才使用。
必须在连接的 客户端和服务器端使用相同的编码:确保这一点的最佳方法是调用mysqli::set_charset()
。使用其他方法可能会使您容易受到编码攻击:
# use as /script.php?name=%bf%27+OR+1+--+
$name = $mysqli->real_escape_string($_GET['name']);
$mysqli->query("SET NAMES 'gbk'"); // sets only on server, not on client
$mysqli->query("SELECT * FROM `users` WHERE `name` ='$name'");
这将提交
SELECT * FROM `users` WHERE `name` = '縗' OR 1 -- '
...请勿使用libmysqlclient
库的vulnerable版本。
在错误修正之前(在MySQL版本4.1.20,5.0.22,5.1.11中),libmysqlclient
容易受到上述编码漏洞的攻击,即使连接字符编码是正确设置。
答案 3 :(得分:-1)
对于sql注入,它是安全的 - 它可以防止在值中使用mysql运算符。
我自己会事先用php验证字符串,给用户一个反馈,出错了,就像这样:
if( ! preg_match('/^[a-f0-9]{32}$/', $md5)) {
// show error message
}
这也可以防止XSS,因为你只能插入字母数字字符串。
如果没有php检查,您有两个主要选项:
A - 从用户输入中删除所有标签:
$safe_input = strip_tags($user_input);
B - 使用编码的html
$safe_input = htmlentites($user_input);
要防止UTF-7 XSS,请在代码顶部指定字符集:
header('Content-Type: text/html; charset=utf-8');
更多关于xss here