首先 - 我知道准备好的陈述是“银弹”而我“应该使用它们” - 然而对于这个项目来说,它是不可行的。相信我,当我说它不能发生时。所以,在讲道开始之前......;)
所以,我今晚在SQL注入上已经阅读了4个小时。
每次使用real_escape_string(我正在使用PHP和MySQL)的反驳说,基本上,real_escape_string不会阻止这一点:
SELECT * FROM something WHERE id=1 or 1=1;
右。明白了。
但是自从大约15年前我第一次接触到mysql以来,我写过的每个查询总是单引用我在查询中发送的所有参数。就像,如果我没有单引号参数,我有这种ikky感觉查询将失败。所以我总是单引一切。所有。的。时间。
和
$_POST['userinput'] is submitted as "1 or 1=1";
$clean = $db->real_escape_string($_POST['userinput']);
$db->query("SELECT * FROM something WHERE id='$clean'");
这怎么可能被打破?它可以?我从来没有见过一个关注不使用不带引号的版本的real_escape_string的例子。
它在引号中。可以突破引用的所有内部引号都被转义。
再次:我知道准备好的陈述是最好的。那不是我要问的。我问我上面写的是不是可以打破?
我看不出办法。
答案 0 :(得分:2)
我相信您的代码是安全的。由于您已将字符串包装在引号中,因此or
被解释为SQL关键字的唯一方法是输入包含结束引号。但是real_escape_string
会逃脱,所以它不会结束字符串。
对于需要整数的值,您还可以做什么
$clean = (int)$_POST['userinput'];
这会将输入1 or 1=1
转换为1
。
答案 1 :(得分:0)
在整数上使用intval()
。
答案 2 :(得分:0)
在某些情况下可以破坏Mysql_real_escape_string。见这里:https://stackoverflow.com/a/12118602/2167896
除了复杂的漏洞之外,如果你没有使用准备好的语句,那么项目中的任何程序员都会犯一个错误而且你已经被软化了。在商业环境中,这严重限制了您可以投入项目的程序员数量,并且绝对需要对每个查询进行质量控制。
如果您计划扩大规模,请认真考虑重写所有查询;您甚至可以使用最新技术和mysql增强功能来提高性能,因此它不会完全丢失。
答案 3 :(得分:0)
事实上,准备好的陈述不是一个特征,而是一个原则。人们可以自己实现它。你必须做的,而不是设计借口。
您想要格式化字符串文字是正确的。这种格式必须通过准备好的声明来完成。
您正在使用的手动格式是分离和可拆卸的。您在一个地方添加引号并在另一个地方转义 - 仅此一项就是许多灾难的来源。即使你在一个地方移动它 - 你的格式仍然可以拆卸,意味着它可以移动到远离实际查询执行的某个地方而忘记那里。
这就是为什么你应该总是使用占位符在查询中表示你的变量,然后在替换它时格式化数据。
这就是为什么准备声明一个银弹,不是因为有人刚刚告诉你的。